<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>StereumLabs Docs Blog</title>
        <link>https://docs.stereumlabs.com/blog</link>
        <description>Neutral, hardware-backed measurements of Ethereum execution and consensus clients.</description>
        <lastBuildDate>Wed, 12 Aug 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <copyright>Copyright © 2026 RockLogic GmbH</copyright>
        <item>
            <title><![CDATA[Where the slot goes: Teku, and the counter that called a syncing node healthy]]></title>
            <link>https://docs.stereumlabs.com/blog/where-the-slot-goes-teku</link>
            <guid>https://docs.stereumlabs.com/blog/where-the-slot-goes-teku</guid>
            <pubDate>Wed, 12 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Teku splits the slot into eleven named stages. Its own counters also rated a node that never committed a block the healthiest of six.]]></description>
            <content:encoded><![CDATA[<p>Teku is the only client in this series that answers the question in the title directly. It splits a block's journey into eleven named stages and counts every one of them, so instead of inferring where the slot goes you can read it off: arrival, gossip validation, pre-state retrieval, the engine call, the state transition, the commit.</p>
<p>In the same three days, on the same six machines, Teku's own counters reported that the healthiest node in the fleet was one that had not committed a single block to its canonical chain.</p>
<p>Both of those are worth your attention, and they are the same story. Teku gives you more slot detail than any other client here, and the detail is carried in metric types that will mislead you at least three separate ways if you read them the way their names suggest.</p>
<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>Read this first</div><div class="admonitionContent_BuS1"><ul>
<li class=""><strong>Reth is excluded again, and this time its block-import and engine metrics argued hard for inclusion.</strong> Teku recorded 21,546 successful block imports on the Reth pairing, the highest of all six, with zero <code>newPayload</code> errors and the fastest engine responses in the fleet. Its container log shows Reth ran the staged-sync pipeline for the entire window and committed no canonical blocks. Teku's own log says <code>Waiting for execution layer sync</code> on all 21,600 slots. One gauge did dissent, <code>beacon_node_syncing_active</code>, and it sits outside the instrument this post is built from. The section below has the details, because the mechanism generalises well beyond our fleet.</li>
<li class=""><strong>Neither of Teku's slot metrics is a Prometheus histogram.</strong> <code>beacon_block_import_delay_counter_total</code> and <code>beacon_engine_requests_total</code> are counters. The latency lives in a string label called <code>interval</code> holding values like <code>[1000,1500)</code>, there is no <code>le</code> label anywhere, and <code>histogram_quantile</code> returns an empty result with an explicit hint. Quantiles have to be computed by hand from the bins.</li>
<li class=""><strong>Three incompatible bucket schemes coexist across those two metrics,</strong> and the only interval string common to all three is <code>[500,1000)</code>. Summing across them without filtering by stage inflates the count elevenfold and moves the apparent median by a factor of roughly seventy.</li>
<li class=""><strong>The unbounded bucket uses a Unicode infinity sign.</strong> It is <code>[12000,∞)</code> with U+221E, not <code>[12000,inf)</code>. A selector written with <code>inf</code> matches nothing and silently drops the entire slow tail, which reads on a dashboard as an absence of slow blocks.</li>
<li class=""><strong>Window and versions.</strong> Three days, 2026-08-03 to 2026-08-06, on Teku 26.7.1 paired with Geth v1.17.5, Nethermind 1.39.2, Besu 26.7.1, Erigon v3.5.4 and Ethrex 23.0.0, on NDC2 bare metal in Vienna. No client version changed inside the window. Every execution client except Reth was confirmed at the chain tip from its own container log at both ends.</li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-eleven-stages">The eleven stages<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-teku#the-eleven-stages" class="hash-link" aria-label="Direct link to The eleven stages" title="Direct link to The eleven stages" translate="no">​</a></h2>
<p><code>beacon_block_import_delay_counter_total</code> carries a <code>stage</code> label with eleven values, and every stage fires once per imported block. Here is where a Geth-paired Teku spent its slots over 21,476 imports:</p>
<p><img decoding="async" loading="lazy" alt="Teku&amp;#39;s eleven block-import stages for the Geth pairing: arrival dominates, with 68% of blocks landing between 1 and 2 seconds, then seven stages complete in under 50 milliseconds each, leaving processed at 100 to 250 milliseconds and the engine wait as the only two stages carrying substantial cost" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDU2MCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNTYwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTAiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjciIGZvbnQtd2VpZ2h0PSI3MDAiPldoZXJlIHRoZSBzbG90IGdvZXMsIHN0YWdlIGJ5IHN0YWdlPC90ZXh0PgogIDx0ZXh0IHg9IjQ4IiB5PSI4MCIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxNiI+VGVrdSAyNi43LjEgcGFpcmVkIHdpdGggR2V0aCB2MS4xNy41IMK3IDIxLDQ3NiBpbXBvcnRlZCBibG9ja3Mgb3ZlciB0aHJlZSBkYXlzIMK3IG1vZGFsIGJ1Y2tldCBwZXIgc3RhZ2U8L3RleHQ+CgogIDwhLS0gdGltZWxpbmUgc2NhbGUgMC4uNDUwMG1zIC0+IHggMjAwLi4xMTQwICgwLjIwODkgcHgvbXMpIC0tPgogIDxnIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIxIj4KICAgIDxsaW5lIHgxPSIyMDAiIHkxPSIxMTgiIHgyPSIyMDAiIHkyPSIzMDAiLz4KICAgIDxsaW5lIHgxPSI0MDkiIHkxPSIxMTgiIHgyPSI0MDkiIHkyPSIzMDAiLz4KICAgIDxsaW5lIHgxPSI2MTgiIHkxPSIxMTgiIHgyPSI2MTgiIHkyPSIzMDAiLz4KICAgIDxsaW5lIHgxPSI4MjciIHkxPSIxMTgiIHgyPSI4MjciIHkyPSIzMDAiLz4KICA8L2c+CiAgPGcgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+CiAgICA8dGV4dCB4PSIyMDAiIHk9IjMxNiI+c2xvdCBzdGFydDwvdGV4dD48dGV4dCB4PSI0MDkiIHk9IjMxNiI+MSBzPC90ZXh0Pjx0ZXh0IHg9IjYxOCIgeT0iMzE2Ij4yIHM8L3RleHQ+PHRleHQgeD0iODI3IiB5PSIzMTYiPjMgczwvdGV4dD4KICA8L2c+CgogIDwhLS0gYXR0ZXN0YXRpb24gZGVhZGxpbmUgYXQgNDAwMG1zIC0tPgogIDxsaW5lIHgxPSIxMDM2IiB5MT0iMTEwIiB4Mj0iMTAzNiIgeTI9IjMwOCIgc3Ryb2tlPSIjZjg3MTcxIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1kYXNoYXJyYXk9IjYgNCIvPgogIDx0ZXh0IHg9IjEwMzAiIHk9IjEyOCIgZmlsbD0iI2Y4NzE3MSIgZm9udC1zaXplPSIxMyIgZm9udC13ZWlnaHQ9IjcwMCIgdGV4dC1hbmNob3I9ImVuZCI+NCBzIGF0dGVzdGF0aW9uIGRlYWRsaW5lPC90ZXh0PgoKICA8IS0tIGluIGZsaWdodCAtLT4KICA8cmVjdCB4PSIyMDAiIHk9IjE1MCIgd2lkdGg9IjIwOSIgaGVpZ2h0PSIzNCIgcng9IjQiIGZpbGw9IiMxZTI5M2IiIHN0cm9rZT0iIzMzNDE1NSIvPgogIDx0ZXh0IHg9IjMwNCIgeT0iMTcyIiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5ibG9jayBpbiBmbGlnaHQ8L3RleHQ+CgogIDwhLS0gYXJyaXZhbCBiYW5kIDEwMDAuLjIwMDAgLS0+CiAgPHJlY3QgeD0iNDA5IiB5PSIxNTAiIHdpZHRoPSIyMDkiIGhlaWdodD0iMzQiIHJ4PSI0IiBmaWxsPSIjNzk4YmZmIi8+CiAgPHRleHQgeD0iNTEzIiB5PSIxNzIiIGZpbGw9IiMwZTE1MzAiIGZvbnQtc2l6ZT0iMTMiIGZvbnQtd2VpZ2h0PSI3MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPmFycml2YWwgwrcgNjglIGxhbmQgaGVyZTwvdGV4dD4KCiAgPCEtLSBwcm9jZXNzaW5nIDIwMDAuLjI1MDAgLS0+CiAgPHJlY3QgeD0iNjE4IiB5PSIxNTAiIHdpZHRoPSIxMDUiIGhlaWdodD0iMzQiIHJ4PSI0IiBmaWxsPSIjMjJjNTVlIi8+CiAgPHRleHQgeD0iNzM1IiB5PSIxNzIiIGZpbGw9IiM4NmVmYWMiIGZvbnQtc2l6ZT0iMTMiPmFsbCBwcm9jZXNzaW5nIMK3IHVuZGVyIDUwMCBtcyBmb3IgOTMlPC90ZXh0PgoKICA8dGV4dCB4PSIyMDAiIHk9IjIxMiIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxNCI+QXJyaXZhbCBpcyBuZXR3b3JrIGFuZCBnb3NzaXAuIEl0IGlzIHRoZSBzYW1lIGZvciBldmVyeSBleGVjdXRpb24gY2xpZW50LCBhbmQgaXQgaXMgbW9zdCBvZiB0aGUgc2xvdC48L3RleHQ+CiAgPHRleHQgeD0iMjAwIiB5PSIyMzQiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTQiPkV2ZXJ5dGhpbmcgVGVrdSBhbmQgdGhlIGV4ZWN1dGlvbiBjbGllbnQgZG8gdG9nZXRoZXIgZml0cyBpbiB0aGUgZ3JlZW4gc2xpdmVyLjwvdGV4dD4KCiAgPCEtLSBzdGFnZSBsaXN0IC0tPgogIDxsaW5lIHgxPSI0OCIgeTE9IjM0OCIgeDI9IjExNTIiIHkyPSIzNDgiIHN0cm9rZT0iIzMzNDE1NSIgc3Ryb2tlLXdpZHRoPSIxIi8+CiAgPHRleHQgeD0iNDgiIHk9IjM3OCIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxNyIgZm9udC13ZWlnaHQ9IjcwMCI+VGhlIG5pbmUgcHJvY2Vzc2luZyBzdGFnZXM8L3RleHQ+CiAgPHRleHQgeD0iMjkwIiB5PSIzNzgiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTQiPnNoYXJlIG9mIGJsb2NrcyBmaW5pc2hpbmcgdGhhdCBzdGFnZSBpbiB1bmRlciA1MCBtczwvdGV4dD4KCiAgPGcgZm9udC1zaXplPSIxMyI+CiAgICA8dGV4dCB4PSI0OCIgeT0iNDEwIiBmaWxsPSIjOGU5YmJkIj50cmFuc2FjdGlvbl9wcmVwYXJlZDwvdGV4dD48dGV4dCB4PSIzMDAiIHk9IjQxMCIgZmlsbD0iIzg2ZWZhYyIgdGV4dC1hbmNob3I9ImVuZCI+OTkuOTklPC90ZXh0PgogICAgPHRleHQgeD0iNDgiIHk9IjQzMiIgZmlsbD0iIzhlOWJiZCI+dHJhbnNhY3Rpb25fY29tbWl0dGVkPC90ZXh0Pjx0ZXh0IHg9IjMwMCIgeT0iNDMyIiBmaWxsPSIjODZlZmFjIiB0ZXh0LWFuY2hvcj0iZW5kIj45OS45OCU8L3RleHQ+CiAgICA8dGV4dCB4PSI0OCIgeT0iNDU0IiBmaWxsPSIjOGU5YmJkIj5kYXRhX2F2YWlsYWJpbGl0eV9jaGVja2VkPC90ZXh0Pjx0ZXh0IHg9IjMwMCIgeT0iNDU0IiBmaWxsPSIjODZlZmFjIiB0ZXh0LWFuY2hvcj0iZW5kIj45OS44NCU8L3RleHQ+CiAgICA8dGV4dCB4PSI0OCIgeT0iNDc2IiBmaWxsPSIjOGU5YmJkIj5iZWdpbl9pbXBvcnRpbmc8L3RleHQ+PHRleHQgeD0iMzAwIiB5PSI0NzYiIGZpbGw9IiM4NmVmYWMiIHRleHQtYW5jaG9yPSJlbmQiPjk5Ljc1JTwvdGV4dD4KCiAgICA8dGV4dCB4PSIzNjAiIHk9IjQxMCIgZmlsbD0iIzhlOWJiZCI+cHJlLXN0YXRlX3JldHJpZXZlZDwvdGV4dD48dGV4dCB4PSI2MTIiIHk9IjQxMCIgZmlsbD0iIzg2ZWZhYyIgdGV4dC1hbmNob3I9ImVuZCI+OTkuNTklPC90ZXh0PgogICAgPHRleHQgeD0iMzYwIiB5PSI0MzIiIGZpbGw9IiM4ZTliYmQiPmdvc3NpcF92YWxpZGF0aW9uPC90ZXh0Pjx0ZXh0IHg9IjYxMiIgeT0iNDMyIiBmaWxsPSIjODZlZmFjIiB0ZXh0LWFuY2hvcj0iZW5kIj45OS41OCU8L3RleHQ+CiAgICA8dGV4dCB4PSIzNjAiIHk9IjQ1NCIgZmlsbD0iIzhlOWJiZCI+Y29tcGxldGVkPC90ZXh0Pjx0ZXh0IHg9IjYxMiIgeT0iNDU0IiBmaWxsPSIjODZlZmFjIiB0ZXh0LWFuY2hvcj0iZW5kIj45OS4zMSU8L3RleHQ+CiAgPC9nPgoKICA8cmVjdCB4PSI2NjAiIHk9IjM5MiIgd2lkdGg9IjQ5MiIgaGVpZ2h0PSI5NiIgcng9IjgiIGZpbGw9IiMxZTI5M2IiIHN0cm9rZT0iI2Y5NzMxNiIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSI2ODAiIHk9IjQxNiIgZmlsbD0iI2ZkZTY4YSIgZm9udC1zaXplPSIxNCIgZm9udC13ZWlnaHQ9IjcwMCI+VGhlIHR3byB0aGF0IGNhcnJ5IHRoZSBjb3N0PC90ZXh0PgogIDx0ZXh0IHg9IjY4MCIgeT0iNDQyIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjEzIj5wcm9jZXNzZWQ8L3RleHQ+CiAgPHRleHQgeD0iMTEzMiIgeT0iNDQyIiBmaWxsPSIjZmI5MjNjIiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0iZW5kIj4xMDAgdG8gMjUwIG1zIGZvciA4OS45JTwvdGV4dD4KICA8dGV4dCB4PSI2ODAiIHk9IjQ2NiIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxMyI+ZXhlY3V0aW9uX3BheWxvYWRfcmVzdWx0X3JlY2VpdmVkPC90ZXh0PgogIDx0ZXh0IHg9IjExMzIiIHk9IjQ2NiIgZmlsbD0iI2ZiOTIzYyIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9ImVuZCI+dW5kZXIgNTAgbXMgZm9yIDg3LjMlPC90ZXh0PgoKICA8dGV4dCB4PSI0OCIgeT0iNTE2IiBmaWxsPSIjZmRlNjhhIiBmb250LXNpemU9IjE1Ij5UaGUgZmlyc3QgYmFyZWx5IG1vdmVzIGFjcm9zcyBleGVjdXRpb24gY2xpZW50cy4gVGhlIHNlY29uZCBtb3ZlcyBieSBuZWFybHkgZml2ZSB0aW1lcywgYW5kIHRoYXQgaXMgdGhlIGV4ZWN1dGlvbiBjbGllbnQncyBjb250cmlidXRpb24uPC90ZXh0PgogIDx0ZXh0IHg9IjQ4IiB5PSI1NDAiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiPmJlYWNvbl9ibG9ja19pbXBvcnRfZGVsYXlfY291bnRlcl90b3RhbCwgcmVzdWx0PSJzdWNjZXNzIi4gQnVja2V0IGVkZ2VzIGFyZSBUZWt1J3MsIHNvIGV2ZXJ5IGZpZ3VyZSBpcyBhIHNoYXJlIHdpdGhpbiBhIGJ1Y2tldCwgbm90IGEgbWVkaWFuLiBTdGFnZSBib3VuZGFyaWVzIG5vdCB2ZXJpZmllZCBhZ2FpbnN0IFRla3UncyBzb3VyY2UuPC90ZXh0PgogIDx0ZXh0IHg9IjExNTIiIHk9IjU0MCIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9ImVuZCI+ZG9jcy5zdGVyZXVtbGFicy5jb208L3RleHQ+Cjwvc3ZnPgo=" width="1200" height="560" class="img_ev3q"></p>
<table><thead><tr><th>Stage</th><th>Modal bucket</th><th>Blocks in it</th></tr></thead><tbody><tr><td>arrival</td><td>1,000 to 1,500 ms</td><td>7,387 of 21,476</td></tr><tr><td>gossip_validation</td><td>under 50 ms</td><td>21,385</td></tr><tr><td>pre-state_retrieved</td><td>under 50 ms</td><td>21,387</td></tr><tr><td>begin_importing</td><td>under 50 ms</td><td>21,422</td></tr><tr><td>transaction_prepared</td><td>under 50 ms</td><td>21,474</td></tr><tr><td>execution_payload_result_received</td><td>under 50 ms</td><td>18,738</td></tr><tr><td>data_availability_checked</td><td>under 50 ms</td><td>21,441</td></tr><tr><td><strong>processed</strong></td><td><strong>100 to 250 ms</strong></td><td><strong>19,307</strong></td></tr><tr><td>transaction_committed</td><td>under 50 ms</td><td>21,471</td></tr><tr><td>completed</td><td>under 50 ms</td><td>21,328</td></tr><tr><td>total_processing_time</td><td>under 500 ms</td><td>19,954</td></tr></tbody></table>
<p>Two of those eleven are not stages in their own right: <code>arrival</code> is time from slot start until the block reached the node, which is network and gossip rather than processing, and <code>total_processing_time</code> is the sum of the rest. That leaves nine processing stages, and seven of them are close to noise. Five of the seven finish in under 50 milliseconds for better than 99% of blocks on every pairing. The other two miss that bar on the slower execution clients: <code>completed</code> runs from 99.31% under Geth down to 98.31% under Erigon, and <code>begin_importing</code> from 99.75% down to 98.86%. Pooled across the five pairings <code>completed</code> sits at 98.96%, so the 99% line does not hold fleet-wide for it. The shortfall is under a percentage point either way. Two stages carry the entire cost: <code>processed</code>, which sits at 100 to 250 ms for around 90% of blocks, and <code>execution_payload_result_received</code>, which is where the engine call is waited on.</p>
<p>That split is the useful part. <code>processed</code> barely moves across pairings, from 84.1% of blocks in the 100-to-250 ms bucket under Besu to 90.5% under Nethermind. Whatever it covers is work Teku does itself. <code>execution_payload_result_received</code> moves by a factor of nearly five. That is the execution client's contribution, isolated by the consensus client's own stopwatch.</p>
<p>One limit before the numbers: we have not verified from Teku's source what each stage boundary corresponds to internally. The stage names are Teku's, the ordering is Teku's, and the durations sum the way you would expect them to, but this is a relative comparison across pairings on one client's instrument rather than an audited decomposition.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-the-engine-wait-costs-per-execution-client">What the engine wait costs, per execution client<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-teku#what-the-engine-wait-costs-per-execution-client" class="hash-link" aria-label="Direct link to What the engine wait costs, per execution client" title="Direct link to What the engine wait costs, per execution client" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="The engine-call wait per execution client under Teku: Ethrex resolves 93.6% of payload results in under 50 milliseconds, Geth 87.3%, Nethermind 74.8%, Besu 56.1% and Erigon 20.4%" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDUyMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNTIwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTAiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjciIGZvbnQtd2VpZ2h0PSI3MDAiPlRoZSBlbmdpbmUgd2FpdCwgaXNvbGF0ZWQgYnkgVGVrdSdzIG93biBzdG9wd2F0Y2g8L3RleHQ+CiAgPHRleHQgeD0iNDgiIHk9IjgwIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE2Ij5zdGFnZT0iZXhlY3V0aW9uX3BheWxvYWRfcmVzdWx0X3JlY2VpdmVkIiDCtyBzaGFyZSBvZiBibG9ja3Mgd2hvc2UgcGF5bG9hZCByZXN1bHQgY2FtZSBiYWNrIGluIHVuZGVyIDUwIG1zPC90ZXh0PgoKICA8IS0tIHNjYWxlIDAuLjEwMCUgLT4geCAyNjAuLjEwNjAgKDggcHggcGVyICUpIC0tPgogIDxnIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIxIj4KICAgIDxsaW5lIHgxPSIyNjAiIHkxPSIxMTAiIHgyPSIyNjAiIHkyPSIzODAiLz4KICAgIDxsaW5lIHgxPSI0NjAiIHkxPSIxMTAiIHgyPSI0NjAiIHkyPSIzODAiLz4KICAgIDxsaW5lIHgxPSI2NjAiIHkxPSIxMTAiIHgyPSI2NjAiIHkyPSIzODAiLz4KICAgIDxsaW5lIHgxPSI4NjAiIHkxPSIxMTAiIHgyPSI4NjAiIHkyPSIzODAiLz4KICAgIDxsaW5lIHgxPSIxMDYwIiB5MT0iMTEwIiB4Mj0iMTA2MCIgeTI9IjM4MCIvPgogIDwvZz4KICA8ZyBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEyIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj4KICAgIDx0ZXh0IHg9IjI2MCIgeT0iNDAwIj4wJTwvdGV4dD48dGV4dCB4PSI0NjAiIHk9IjQwMCI+MjUlPC90ZXh0Pjx0ZXh0IHg9IjY2MCIgeT0iNDAwIj41MCU8L3RleHQ+PHRleHQgeD0iODYwIiB5PSI0MDAiPjc1JTwvdGV4dD48dGV4dCB4PSIxMDYwIiB5PSI0MDAiPjEwMCU8L3RleHQ+CiAgPC9nPgoKICA8dGV4dCB4PSIxMDkwIiB5PSIxMjgiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiIHRleHQtYW5jaG9yPSJlbmQiPmF0IDEgcyBvciB3b3JzZTwvdGV4dD4KCiAgPHRleHQgeD0iMjUwIiB5PSIxNTAiIGZpbGw9IiM4NmVmYWMiIGZvbnQtc2l6ZT0iMTUiIGZvbnQtd2VpZ2h0PSI3MDAiIHRleHQtYW5jaG9yPSJlbmQiPkV0aHJleCAyMy4wLjA8L3RleHQ+CiAgPHJlY3QgeD0iMjYwIiB5PSIxMzIiIHdpZHRoPSI3NDguOCIgaGVpZ2h0PSIyNiIgcng9IjMiIGZpbGw9IiMyMmM1NWUiLz4KICA8dGV4dCB4PSIxMDIwIiB5PSIxNTEiIGZpbGw9IiM4NmVmYWMiIGZvbnQtc2l6ZT0iMTQiIGZvbnQtd2VpZ2h0PSI3MDAiPjkzLjYlPC90ZXh0PgogIDx0ZXh0IHg9IjExNTIiIHk9IjE1MSIgZmlsbD0iIzhlOWJiZCIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9ImVuZCI+MS45JTwvdGV4dD4KCiAgPHRleHQgeD0iMjUwIiB5PSIyMDAiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTUiIHRleHQtYW5jaG9yPSJlbmQiPkdldGggdjEuMTcuNTwvdGV4dD4KICA8cmVjdCB4PSIyNjAiIHk9IjE4MiIgd2lkdGg9IjY5OC40IiBoZWlnaHQ9IjI2IiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPgogIDx0ZXh0IHg9Ijk3MCIgeT0iMjAxIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0Ij44Ny4zJTwvdGV4dD4KICA8dGV4dCB4PSIxMTUyIiB5PSIyMDEiIGZpbGw9IiM4ZTliYmQiIGZvbnQtc2l6ZT0iMTMiIHRleHQtYW5jaG9yPSJlbmQiPjIuMSU8L3RleHQ+CgogIDx0ZXh0IHg9IjI1MCIgeT0iMjUwIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE1IiB0ZXh0LWFuY2hvcj0iZW5kIj5OZXRoZXJtaW5kIDEuMzkuMjwvdGV4dD4KICA8cmVjdCB4PSIyNjAiIHk9IjIzMiIgd2lkdGg9IjU5OC40IiBoZWlnaHQ9IjI2IiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPgogIDx0ZXh0IHg9Ijg3MCIgeT0iMjUxIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0Ij43NC44JTwvdGV4dD4KICA8dGV4dCB4PSIxMTUyIiB5PSIyNTEiIGZpbGw9IiM4ZTliYmQiIGZvbnQtc2l6ZT0iMTMiIHRleHQtYW5jaG9yPSJlbmQiPjUuNiU8L3RleHQ+CgogIDx0ZXh0IHg9IjI1MCIgeT0iMzAwIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE1IiB0ZXh0LWFuY2hvcj0iZW5kIj5CZXN1IDI2LjcuMTwvdGV4dD4KICA8cmVjdCB4PSIyNjAiIHk9IjI4MiIgd2lkdGg9IjQ0OC44IiBoZWlnaHQ9IjI2IiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPgogIDx0ZXh0IHg9IjcyMCIgeT0iMzAxIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0Ij41Ni4xJTwvdGV4dD4KICA8dGV4dCB4PSIxMTUyIiB5PSIzMDEiIGZpbGw9IiM4ZTliYmQiIGZvbnQtc2l6ZT0iMTMiIHRleHQtYW5jaG9yPSJlbmQiPjQuNyU8L3RleHQ+CgogIDx0ZXh0IHg9IjI1MCIgeT0iMzUwIiBmaWxsPSIjZmI5MjNjIiBmb250LXNpemU9IjE1IiBmb250LXdlaWdodD0iNzAwIiB0ZXh0LWFuY2hvcj0iZW5kIj5Fcmlnb24gdjMuNS40PC90ZXh0PgogIDxyZWN0IHg9IjI2MCIgeT0iMzMyIiB3aWR0aD0iMTYzLjIiIGhlaWdodD0iMjYiIHJ4PSIzIiBmaWxsPSIjZjk3MzE2Ii8+CiAgPHRleHQgeD0iNDM1IiB5PSIzNTEiIGZpbGw9IiNmYjkyM2MiIGZvbnQtc2l6ZT0iMTQiIGZvbnQtd2VpZ2h0PSI3MDAiPjIwLjQlPC90ZXh0PgogIDx0ZXh0IHg9IjExNTIiIHk9IjM1MSIgZmlsbD0iI2ZiOTIzYyIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9ImVuZCI+OS40JTwvdGV4dD4KCiAgPHRleHQgeD0iNDgiIHk9IjQ0MCIgZmlsbD0iI2ZkZTY4YSIgZm9udC1zaXplPSIxNSI+RXRocmV4IGZhc3Rlc3QgYW5kIEVyaWdvbiBzbG93ZXN0LCBub3cgb24gdGhlIGZpZnRoIGNvbnNlbnN1cyBjbGllbnQgdG8gbWVhc3VyZSBpdC4gVGhlIG1pZGRsZSBwZXJtdXRlcyBhZ2FpbiwgYW5kIGhlcmUgaXQgcGVybXV0ZXM8L3RleHQ+CiAgPHRleHQgeD0iNDgiIHk9IjQ2MiIgZmlsbD0iI2ZkZTY4YSIgZm9udC1zaXplPSIxNSI+aW5zaWRlIG9uZSBpbnN0cnVtZW50OiBOZXRoZXJtaW5kIGlzIHNlY29uZCBvbiBoZWFkIHNwZWVkIGFuZCBmb3VydGggb24gdGFpbCwgR2V0aCB0aGlyZCBvbiBoZWFkIGFuZCBzZWNvbmQgb24gdGFpbC48L3RleHQ+CiAgPHRleHQgeD0iNDgiIHk9IjQ5MiIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMiI+UmV0aCBleGNsdWRlZDogaXQgd2FzIGluIHN0YWdlZCBzeW5jIGFsbCB3aW5kb3cgYW5kIGFuc3dlcmVkIGluc3RhbnRseSB3aXRob3V0IGV4ZWN1dGluZy4gRXRocmV4J3MgZGVub21pbmF0b3IgaXMgYWJvdXQgMiUgc21hbGxlciB0aGFuIGl0cyBwZWVycywgd2hpY2ggZG9lcyBub3QgY2hhbmdlIGl0cyByYW5rLjwvdGV4dD4KICA8dGV4dCB4PSIxMTUyIiB5PSI0OTIiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiIHRleHQtYW5jaG9yPSJlbmQiPmRvY3Muc3RlcmV1bWxhYnMuY29tPC90ZXh0Pgo8L3N2Zz4K" width="1200" height="520" class="img_ev3q"></p>
<table><thead><tr><th>Execution client</th><th>Result under 50 ms</th><th>Result at 1 s or worse</th><th><code>newPayload</code> under 100 ms</th><th><code>newPayload</code> at 1 s or worse</th></tr></thead><tbody><tr><td><strong>Ethrex</strong> 23.0.0</td><td><strong>93.6%</strong></td><td>1.9%</td><td><strong>87.6%</strong></td><td><strong>2.6%</strong></td></tr><tr><td><strong>Geth</strong> v1.17.5</td><td>87.3%</td><td><strong>2.1%</strong></td><td>37.5%</td><td>3.0%</td></tr><tr><td><strong>Nethermind</strong> 1.39.2</td><td>74.8%</td><td>5.6%</td><td>42.2%</td><td>7.3%</td></tr><tr><td><strong>Besu</strong> 26.7.1</td><td>56.1%</td><td>4.7%</td><td>7.6%</td><td>6.7%</td></tr><tr><td><strong>Erigon</strong> v3.5.4</td><td><strong>20.4%</strong></td><td><strong>9.4%</strong></td><td><strong>2.6%</strong></td><td><strong>12.3%</strong></td></tr></tbody></table>
<p>The two leftmost columns come from the block-import stage, the two rightmost from <code>beacon_engine_requests_total{method="new_payloadV4"}</code>. They are separate instruments inside the same process, and they agree at both extremes.</p>
<p>This is the fifth consensus client to put Ethrex at the fast end and Erigon at the slow end of <code>newPayload</code>, which is now the most heavily replicated result in this series. The middle of the field permutes again, and this time it permutes within a single instrument depending on which statistic you read. Ranked by the fastest bucket, Nethermind is second and Geth third. Ranked by the share of calls at a second or worse, Geth is second and Nethermind fourth. Nethermind is bimodal: a large fast mode paired with a fat tail. Geth has a slower mode and a thinner tail. Pick either column alone and you get a different middle.</p>
<p>Errors are rare and instructive: 40 failed <code>newPayload</code> calls across the five clients over three days, and every single one of them landed in the <code>[5000,∞)</code> bucket. Erigon 15, Nethermind 11, Besu 10, Ethrex 2, Geth 2. Nothing failed quickly. That pattern is what a fixed client-side timeout looks like, though we did not confirm Teku's timeout value or find an error-reason label, so treat the cause as inferred rather than measured.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="besus-head-update-now-on-a-fifth-instrument">Besu's head update, now on a fifth instrument<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-teku#besus-head-update-now-on-a-fifth-instrument" class="hash-link" aria-label="Direct link to Besu's head update, now on a fifth instrument" title="Direct link to Besu's head update, now on a fifth instrument" translate="no">​</a></h2>
<p><code>forkchoiceUpdated</code> again separates Besu from everyone else:</p>
<table><thead><tr><th>Execution client</th><th><code>forkchoiceUpdated</code> under 100 ms</th><th>Modal bucket</th></tr></thead><tbody><tr><td>Geth</td><td>99.88%</td><td>under 100 ms</td></tr><tr><td>Ethrex</td><td>99.80%</td><td>under 100 ms</td></tr><tr><td>Nethermind</td><td>99.74%</td><td>under 100 ms</td></tr><tr><td>Erigon</td><td>96.54%</td><td>under 100 ms</td></tr><tr><td><strong>Besu</strong></td><td><strong>14.84%</strong></td><td><strong>100 to 300 ms</strong></td></tr></tbody></table>
<p>Four of five clients answer the head-update call in under 100 milliseconds better than 96% of the time. Besu does so 14.8% of the time, and its modal bucket is 100 to 300 ms, holding 77.5% of its calls.</p>
<p>Teku's fastest bucket is 100 ms wide, too coarse to resolve the peer values the earlier instruments reported for Besu: 4.3 to 7.4 ms under Grandine, 4.3 to 9.9 ms under Prysm, 5.8 to 14.5 ms under Lighthouse. Nimbus is the exception it was in part four, with peers running from 63 to 262 ms and two of them slower than its own Besu. So this instrument cannot reproduce the size of the gap. What it can do is place Besu, and only Besu, in a slower bucket than the rest of the field, which is consistent with the 162-to-200 ms figure the four earlier instruments measured directly. Five instruments have now timed this call and all five put Besu's head update above 100 ms. Four of them also put Besu behind every peer. The magnitude holds on five, the gap on four.</p>
<p>Worth repeating from part three: this cost is not attestation budget. <code>forkchoiceUpdated</code> does not sit between a block arriving and that block becoming attestable.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-counter-that-called-a-syncing-node-healthy">The counter that called a syncing node healthy<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-teku#the-counter-that-called-a-syncing-node-healthy" class="hash-link" aria-label="Direct link to The counter that called a syncing node healthy" title="Direct link to The counter that called a syncing node healthy" translate="no">​</a></h2>
<p>Reth was excluded from parts one through four. Going into this edition its metrics said that was over.</p>
<p><img decoding="async" loading="lazy" alt="Teku&amp;#39;s metrics ranked the Reth pairing best in the fleet on five separate counters while Teku&amp;#39;s own log reported waiting for execution layer sync on all 21,600 slots of the window" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDU2MCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNTYwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTAiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjciIGZvbnQtd2VpZ2h0PSI3MDAiPk9uZSBwcm9jZXNzLCB0d28gYWNjb3VudHMgb2YgdGhlIHNhbWUgdGhyZWUgZGF5czwvdGV4dD4KICA8dGV4dCB4PSI0OCIgeT0iODAiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTYiPlRla3UgMjYuNy4xIHBhaXJlZCB3aXRoIFJldGggdjIuNC4xIMK3IDIwMjYtMDgtMDMgdG8gMjAyNi0wOC0wNiDCtyBib3RoIGNvbHVtbnMgYXJlIFRla3UncyBvd24gb3V0cHV0PC90ZXh0PgoKICA8IS0tIExFRlQ6IG1ldHJpY3MgLS0+CiAgPHRleHQgeD0iNjAiIHk9IjEzMCIgZmlsbD0iIzg2ZWZhYyIgZm9udC1zaXplPSIxNyIgZm9udC13ZWlnaHQ9IjcwMCI+V2hhdCBUZWt1J3MgYmxvY2staW1wb3J0IGFuZCBlbmdpbmUgY291bnRlcnMgcmVwb3J0ZWQ8L3RleHQ+CiAgPHJlY3QgeD0iNjAiIHk9IjE0NiIgd2lkdGg9IjUxMCIgaGVpZ2h0PSIyNTAiIHJ4PSI4IiBmaWxsPSIjMGYyYTFjIiBzdHJva2U9IiMyYjRhMzciIHN0cm9rZS13aWR0aD0iMSIvPgoKICA8ZyBmb250LXNpemU9IjE0Ij4KICAgIDx0ZXh0IHg9IjgyIiB5PSIxODIiIGZpbGw9IiNjZGQ2ZjQiPnN1Y2Nlc3NmdWwgYmxvY2sgaW1wb3J0czwvdGV4dD4KICAgIDx0ZXh0IHg9IjQ3MCIgeT0iMTgyIiBmaWxsPSIjODZlZmFjIiBmb250LXdlaWdodD0iNzAwIiB0ZXh0LWFuY2hvcj0iZW5kIj4yMSw1NDY8L3RleHQ+CiAgICA8dGV4dCB4PSI1NTAiIHk9IjE4MiIgZmlsbD0iIzIyYzU1ZSIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9ImVuZCI+YmVzdCBvZiA2PC90ZXh0PgoKICAgIDx0ZXh0IHg9IjgyIiB5PSIyMjIiIGZpbGw9IiNjZGQ2ZjQiPm5ld1BheWxvYWQgZXJyb3JzPC90ZXh0PgogICAgPHRleHQgeD0iNDcwIiB5PSIyMjIiIGZpbGw9IiM4NmVmYWMiIGZvbnQtd2VpZ2h0PSI3MDAiIHRleHQtYW5jaG9yPSJlbmQiPjA8L3RleHQ+CiAgICA8dGV4dCB4PSI1NTAiIHk9IjIyMiIgZmlsbD0iIzIyYzU1ZSIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9ImVuZCI+YmVzdCBvZiA2PC90ZXh0PgoKICAgIDx0ZXh0IHg9IjgyIiB5PSIyNjIiIGZpbGw9IiNjZGQ2ZjQiPmZhaWxlZCBwYXlsb2FkIGV4ZWN1dGlvbnM8L3RleHQ+CiAgICA8dGV4dCB4PSI0NzAiIHk9IjI2MiIgZmlsbD0iIzg2ZWZhYyIgZm9udC13ZWlnaHQ9IjcwMCIgdGV4dC1hbmNob3I9ImVuZCI+MDwvdGV4dD4KICAgIDx0ZXh0IHg9IjU1MCIgeT0iMjYyIiBmaWxsPSIjMjJjNTVlIiBmb250LXNpemU9IjEyIiB0ZXh0LWFuY2hvcj0iZW5kIj5iZXN0IG9mIDY8L3RleHQ+CgogICAgPHRleHQgeD0iODIiIHk9IjMwMiIgZmlsbD0iI2NkZDZmNCI+cmVjb3JkZWQgYXMgInN5bmNpbmciPC90ZXh0PgogICAgPHRleHQgeD0iNDcwIiB5PSIzMDIiIGZpbGw9IiM4NmVmYWMiIGZvbnQtd2VpZ2h0PSI3MDAiIHRleHQtYW5jaG9yPSJlbmQiPjA8L3RleHQ+CiAgICA8dGV4dCB4PSI1NTAiIHk9IjMwMiIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9ImVuZCI+dGllZCwgYWxsIDY8L3RleHQ+CgogICAgPHRleHQgeD0iODIiIHk9IjM0MiIgZmlsbD0iI2NkZDZmNCI+cGF5bG9hZCByZXN1bHQgdW5kZXIgNTAgbXM8L3RleHQ+CiAgICA8dGV4dCB4PSI0NzAiIHk9IjM0MiIgZmlsbD0iIzg2ZWZhYyIgZm9udC13ZWlnaHQ9IjcwMCIgdGV4dC1hbmNob3I9ImVuZCI+OTUuNyU8L3RleHQ+CiAgICA8dGV4dCB4PSI1NTAiIHk9IjM0MiIgZmlsbD0iIzIyYzU1ZSIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9ImVuZCI+YmVzdCBvZiA2PC90ZXh0PgogIDwvZz4KICA8dGV4dCB4PSI4MiIgeT0iMzc4IiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEzIj5Gb3VyIGZpcnN0IHBsYWNlcywgYW5kIGEgdGllIGF0IHplcm8gb24gdGhlIG9uZSBuYW1lZCBmb3IgdGhpcy48L3RleHQ+CgogIDwhLS0gUklHSFQ6IGxvZyAtLT4KICA8dGV4dCB4PSI2MzAiIHk9IjEzMCIgZmlsbD0iI2ZjYTVhNSIgZm9udC1zaXplPSIxNyIgZm9udC13ZWlnaHQ9IjcwMCI+V2hhdCBUZWt1J3MgbG9nIHJlcG9ydGVkPC90ZXh0PgogIDxyZWN0IHg9IjYzMCIgeT0iMTQ2IiB3aWR0aD0iNTEwIiBoZWlnaHQ9IjI1MCIgcng9IjgiIGZpbGw9IiMxZTI5M2IiIHN0cm9rZT0iIzNmMjUzMCIgc3Ryb2tlLXdpZHRoPSIxIi8+CgogIDx0ZXh0IHg9IjY1MiIgeT0iMTc2IiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEyIiBmb250LWZhbWlseT0ibW9ub3NwYWNlIj4yMDI2LTA4LTA1IDIzOjU5OjU5LjE0NSBJTkZPPC90ZXh0PgogIDx0ZXh0IHg9IjY1MiIgeT0iMjAwIiBmaWxsPSIjZmNhNWE1IiBmb250LXNpemU9IjEzIiBmb250LWZhbWlseT0ibW9ub3NwYWNlIj5TeW5jaW5nICoqKiBTbG90OiAxNDkyOTE5OCw8L3RleHQ+CiAgPHRleHQgeD0iNjUyIiB5PSIyMjAiIGZpbGw9IiNmY2E1YTUiIGZvbnQtc2l6ZT0iMTMiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiPkhlYWQgc2xvdDogMTQ5MjkxOTcsPC90ZXh0PgogIDx0ZXh0IHg9IjY1MiIgeT0iMjQwIiBmaWxsPSIjZmNhNWE1IiBmb250LXNpemU9IjEzIiBmb250LWZhbWlseT0ibW9ub3NwYWNlIj5XYWl0aW5nIGZvciBleGVjdXRpb24gbGF5ZXIgc3luYyw8L3RleHQ+CiAgPHRleHQgeD0iNjUyIiB5PSIyNjAiIGZpbGw9IiNmY2E1YTUiIGZvbnQtc2l6ZT0iMTMiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiPkNvbm5lY3RlZCBwZWVyczogMTAwPC90ZXh0PgoKICA8bGluZSB4MT0iNjUyIiB5MT0iMjg0IiB4Mj0iMTExOCIgeTI9IjI4NCIgc3Ryb2tlPSIjMzM0MTU1IiBzdHJva2Utd2lkdGg9IjEiLz4KICA8dGV4dCB4PSI2NTIiIHk9IjMxNiIgZmlsbD0iI2Y4NzE3MSIgZm9udC1zaXplPSI0MCIgZm9udC13ZWlnaHQ9IjcwMCI+MjEsNjAwPC90ZXh0PgogIDx0ZXh0IHg9IjgyMCIgeT0iMzE2IiBmaWxsPSIjZmNhNWE1IiBmb250LXNpemU9IjE2Ij5vZiAyMSw2MDAgc2xvdHM8L3RleHQ+CiAgPHRleHQgeD0iNjUyIiB5PSIzNDQiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTMiPkV2ZXJ5IHNsb3QgaW4gdGhlIHdpbmRvdy4gVGhyZWUgZGF5cy4gTm8gZXhjZXB0aW9uLjwvdGV4dD4KICA8dGV4dCB4PSI2NTIiIHk9IjM3MiIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMyI+UmV0aCBsb2dnZWQgMCBjYW5vbmljYWwgY29tbWl0cyBhbmQgcmFuIHBpcGVsaW5lIHN0YWdlIDQvMTQgdG8gOS8xNC48L3RleHQ+CgogIDwhLS0gYm90dG9tIC0tPgogIDxyZWN0IHg9IjQ4IiB5PSI0MjAiIHdpZHRoPSIxMTA0IiBoZWlnaHQ9IjcyIiByeD0iOCIgZmlsbD0iIzFlMjkzYiIgc3Ryb2tlPSIjZjk3MzE2IiBzdHJva2Utd2lkdGg9IjEuNSIvPgogIDx0ZXh0IHg9IjcyIiB5PSI0NTAiIGZpbGw9IiNmZGU2OGEiIGZvbnQtc2l6ZT0iMTYiIGZvbnQtd2VpZ2h0PSI3MDAiPlRoZSBmYXN0ZXN0IGVuZ2luZSByZXNwb25zZXMgaW4gdGhlIGZsZWV0IGNhbWUgZnJvbSB0aGUgbm9kZSBkb2luZyBub25lIG9mIHRoZSB3b3JrLjwvdGV4dD4KICA8dGV4dCB4PSI3MiIgeT0iNDc2IiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0Ij5BbiBleGVjdXRpb24gY2xpZW50IHRoYXQgaXMgbm90IGV4ZWN1dGluZyBhbnN3ZXJzIGltbWVkaWF0ZWx5LiBPcHRpbWlzdGljIHN5bmMgdGhlbiByZWNvcmRzIHRoZSBpbXBvcnQgYXMgYSBzdWNjZXNzLCBzbyBubyBjb3VudGVyIGluIHRoaXMgaW5zdHJ1bWVudCBkaXNzZW50cy48L3RleHQ+CgogIDx0ZXh0IHg9IjQ4IiB5PSI1MTgiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiPk9uZSBnYXVnZSBvdXRzaWRlIGl0IGRpZDogYmVhY29uX25vZGVfc3luY2luZ19hY3RpdmUgcmVhZCAxIG9uIGFsbCA0LDMyMCBzY3JhcGVzIGhlcmUsIGFnYWluc3QgMCBvbiBHZXRoIGFuZCBCZXN1LiBJdCBzYXlzIHRoZSBiZWFjb24gbm9kZSBpcyBvZmYgdGhlIHRpcCwgbm90IHRoYXQgdGhlIGV4ZWN1dGlvbiBsYXllciBpcyB3aHkuPC90ZXh0PgogIDx0ZXh0IHg9IjQ4IiB5PSI1MzYiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiPkNvbnRyb2w6IHRoZSBzYW1lIFJldGggYnVpbGQgcGFpcmVkIHdpdGggTGlnaHRob3VzZSwgc2FtZSBmbGVldCBhbmQgd2luZG93LCBsb2dnZWQgIkNhbm9uaWNhbCBjaGFpbiBjb21taXR0ZWQiIDYsNDUyIHRpbWVzLiBUaGF0IHRoZSBzdWNjZXNzIHJlc3VsdCBjb21lcyBmcm9tIG9wdGltaXN0aWMgaW1wb3J0IGlzIG91ciByZWFkaW5nIG9mIHRoZSBzcGVjLCBub3QgYSBtZWFzdXJlbWVudC48L3RleHQ+CiAgPHRleHQgeD0iMTE1MiIgeT0iNTI0IiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEyIiB0ZXh0LWFuY2hvcj0iZW5kIj5kb2NzLnN0ZXJldW1sYWJzLmNvbTwvdGV4dD4KPC9zdmc+Cg==" width="1200" height="560" class="img_ev3q"></p>
<table><thead><tr><th>What Teku's metrics said about Reth</th><th>Value</th><th>Rank of six</th></tr></thead><tbody><tr><td>Successful block imports</td><td>21,546</td><td>best</td></tr><tr><td><code>newPayload</code> errors</td><td>0</td><td>best</td></tr><tr><td>Failed payload executions</td><td>0</td><td>best</td></tr><tr><td>Payload results under 50 ms</td><td>95.7%</td><td>best</td></tr><tr><td>Blocks recorded as <code>failed_execution_payload_execution_syncing</code></td><td>0</td><td>tied, all six</td></tr></tbody></table>
<p>Four first places and a tie at zero on the one counter whose name promises to catch this. By its consensus client's block-import and engine instrumentation, Reth was the healthiest and fastest execution client on the fleet.</p>
<p>Note the first row against the window's chain: Reth recorded 21,546 imports where the chain produced 21,531 blocks. The counter counts import events rather than canonical blocks, so it can exceed the block count, and on a node that is optimistically importing without validating there is nothing to pull it back down.</p>
<p>Here is Teku's log on that same host, at the same moment, and it wrote a variant of this line every twelve seconds:</p>
<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">2026-08-05 23:59:59.145 INFO - Syncing *** Slot: 14929198, Head slot: 14929197,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Waiting for execution layer sync, Connected peers: 100</span><br></span></code></pre></div></div>
<p>That line appeared <strong>21,600 times in 21,600 slots</strong>. Every slot in the window, without a single exception, on all three days. On the Geth pairing the corresponding line is <code>Slot Event *** Slot: 14929198, Block: dcba1324..., Justified: 466536, Finalized: 466535</code>, and <code>Waiting for execution layer sync</code> appears zero times.</p>
<p>Reth's own log agrees with Teku's log and disagrees with Teku's metrics:</p>
<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">2026-08-05T23:59:59.829405Z INFO reth_node_events::node: Committed stage progress</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">pipeline_stages=9/14 stage=MerkleExecute checkpoint=0 target=25588987 stage_progress=40.05%</span><br></span></code></pre></div></div>
<p>It was running the staged-sync pipeline, which advanced from stage 4 of 14 at the start of the window to stage 9 of 14 at the end, against a pipeline target roughly 103,000 blocks behind the live chain head of 25,692,170. <code>Canonical chain committed</code> appears zero times in three days. The control that makes this airtight: the identical Reth build paired with Lighthouse, on the same fleet over the same window, logged that line 6,452 times.</p>
<p>The mechanism is optimistic sync, and it is doing what the specification asks of it. When the execution client cannot yet validate a payload, the consensus client may import the block optimistically and carry on. Teku's block-import counter records that as <code>result="success"</code>, because from the consensus layer's point of view the import did succeed. The <code>_syncing</code> result value exists but stayed at zero, so it cannot be used as the guard either.</p>
<p>The timing consequence is the one that would have produced a false finding here. Reth answered 95.7% of payload requests in under 50 milliseconds, better than any synced client. An execution client that is not executing returns immediately. <strong>The fastest engine responses in the fleet came from the node doing none of the work,</strong> and every block-import and engine counter presented that as excellence.</p>
<p>The container log is how we caught it, and it is not the only thing that could have. Teku's <code>beacon_node_syncing_active</code> gauge read 1 on all 4,320 scrapes of the window on the Reth pairing, against at most 5 scrapes of 4,320 on any other pairing, and 0 on Geth and Besu. That gauge sits outside the eleven-stage instrument this whole post is built from, so a dashboard assembled around block import never shows it. What it will not do is name the cause: it also reached 1 on the Ethrex pairing, where <code>Waiting for execution layer sync</code> never appears in the log at all.</p>
<p>So the lesson is narrower than "metrics cannot tell you" and more useful. The gauge tells you the beacon node is off the tip. The log tells you the execution layer is why. Every counter that a slot-timing dashboard would plausibly carry rated a node that committed nothing the best in the fleet, and the one series that dissented is the one no block-import dashboard has on it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="three-ways-the-buckets-will-lie-to-you">Three ways the buckets will lie to you<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-teku#three-ways-the-buckets-will-lie-to-you" class="hash-link" aria-label="Direct link to Three ways the buckets will lie to you" title="Direct link to Three ways the buckets will lie to you" translate="no">​</a></h2>
<p>The instrument that produced everything above needs handling. All of these are properties of Teku 26.7.1 as deployed, and all of them are silent failures rather than errors.</p>
<p><img decoding="async" loading="lazy" alt="Teku&amp;#39;s three incompatible interval bucket schemes: a ten-bucket coarse scheme, a seven-bucket fine scheme, and an eight-bucket engine scheme, sharing only the string 500 to 1000 milliseconds" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDU0MCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNTQwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTAiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjciIGZvbnQtd2VpZ2h0PSI3MDAiPlRocmVlIGJ1Y2tldCBzY2hlbWVzLCBvbmUgbGFiZWwgbmFtZTwvdGV4dD4KICA8dGV4dCB4PSI0OCIgeT0iODAiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTYiPlRla3UgY2FycmllcyBsYXRlbmN5IGFzIGEgc3RyaW5nIGluIGEgbGFiZWwgY2FsbGVkICJpbnRlcnZhbCIuIFRoZXNlIGFyZSB0aGUgdGhyZWUgc2V0cyBvZiBlZGdlcyBpdCB1c2VzLjwvdGV4dD4KCiAgPCEtLSBzY2hlbWUgcm93cyAtLT4KICA8dGV4dCB4PSI0OCIgeT0iMTMwIiBmaWxsPSIjNzk4YmZmIiBmb250LXNpemU9IjE1IiBmb250LXdlaWdodD0iNzAwIj5DT0FSU0UgwrcgMTAgYnVja2V0czwvdGV4dD4KICA8dGV4dCB4PSI0OCIgeT0iMTUwIiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEyIj5zdGFnZT0iYXJyaXZhbCIgYW5kICJ0b3RhbF9wcm9jZXNzaW5nX3RpbWUiPC90ZXh0PgogIDxnIGZvbnQtc2l6ZT0iMTIiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZpbGw9IiNjZGQ2ZjQiPgogICAgPHRleHQgeD0iMzMwIiB5PSIxMzYiPlswLDUwMCk8L3RleHQ+PHRleHQgeD0iNDI1IiB5PSIxMzYiPlsxMDAwLDE1MDApPC90ZXh0Pjx0ZXh0IHg9IjU0NSIgeT0iMTM2Ij5bMTUwMCwyMDAwKTwvdGV4dD48dGV4dCB4PSI2NjUiIHk9IjEzNiI+WzIwMDAsMzAwMCk8L3RleHQ+PHRleHQgeD0iNzg1IiB5PSIxMzYiPlszMDAwLDQwMDApPC90ZXh0PgogICAgPHRleHQgeD0iMzMwIiB5PSIxNTYiPls0MDAwLDUwMDApPC90ZXh0Pjx0ZXh0IHg9IjQ1MCIgeT0iMTU2Ij5bNTAwMCw4MDAwKTwvdGV4dD48dGV4dCB4PSI1NzAiIHk9IjE1NiI+WzgwMDAsMTIwMDApPC90ZXh0PgogIDwvZz4KICA8cmVjdCB4PSI2OTQiIHk9IjE0NCIgd2lkdGg9IjEwNiIgaGVpZ2h0PSIxOCIgcng9IjMiIGZpbGw9IiMzZjI1MzAiLz4KICA8dGV4dCB4PSI3MDAiIHk9IjE1NyIgZmlsbD0iI2ZjYTVhNSIgZm9udC1zaXplPSIxMiIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSI+WzEyMDAwLOKInik8L3RleHQ+CgogIDx0ZXh0IHg9IjQ4IiB5PSIyMTIiIGZpbGw9IiMyMmM1NWUiIGZvbnQtc2l6ZT0iMTUiIGZvbnQtd2VpZ2h0PSI3MDAiPkZJTkUgwrcgNyBidWNrZXRzPC90ZXh0PgogIDx0ZXh0IHg9IjQ4IiB5PSIyMzIiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiPnRoZSBvdGhlciBuaW5lIHN0YWdlczwvdGV4dD4KICA8ZyBmb250LXNpemU9IjEyIiBmb250LWZhbWlseT0ibW9ub3NwYWNlIiBmaWxsPSIjY2RkNmY0Ij4KICAgIDx0ZXh0IHg9IjMzMCIgeT0iMjE4Ij5bMCw1MCk8L3RleHQ+PHRleHQgeD0iNDEwIiB5PSIyMTgiPls1MCwxMDApPC90ZXh0Pjx0ZXh0IHg9IjUwMCIgeT0iMjE4Ij5bMTAwLDI1MCk8L3RleHQ+PHRleHQgeD0iNjAwIiB5PSIyMTgiPlsyNTAsNTAwKTwvdGV4dD48dGV4dCB4PSI3MDAiIHk9IjIxOCI+WzEwMDAsMjAwMCk8L3RleHQ+CiAgPC9nPgogIDxyZWN0IHg9IjMzMCIgeT0iMjI2IiB3aWR0aD0iODYiIGhlaWdodD0iMTgiIHJ4PSIzIiBmaWxsPSIjM2YyNTMwIi8+CiAgPHRleHQgeD0iMzM2IiB5PSIyMzkiIGZpbGw9IiNmY2E1YTUiIGZvbnQtc2l6ZT0iMTIiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiPlsyMDAwLOKInik8L3RleHQ+CgogIDx0ZXh0IHg9IjQ4IiB5PSIyOTQiIGZpbGw9IiNmZGU2OGEiIGZvbnQtc2l6ZT0iMTUiIGZvbnQtd2VpZ2h0PSI3MDAiPkVOR0lORSDCtyA4IGJ1Y2tldHM8L3RleHQ+CiAgPHRleHQgeD0iNDgiIHk9IjMxNCIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMiI+YmVhY29uX2VuZ2luZV9yZXF1ZXN0c190b3RhbDwvdGV4dD4KICA8ZyBmb250LXNpemU9IjEyIiBmb250LWZhbWlseT0ibW9ub3NwYWNlIiBmaWxsPSIjY2RkNmY0Ij4KICAgIDx0ZXh0IHg9IjMzMCIgeT0iMzAwIj5bMCwxMDApPC90ZXh0Pjx0ZXh0IHg9IjQyMCIgeT0iMzAwIj5bMTAwLDMwMCk8L3RleHQ+PHRleHQgeD0iNTIwIiB5PSIzMDAiPlszMDAsNTAwKTwvdGV4dD48dGV4dCB4PSI2MjAiIHk9IjMwMCI+WzEwMDAsMjAwMCk8L3RleHQ+PHRleHQgeD0iNzQwIiB5PSIzMDAiPlsyMDAwLDMwMDApPC90ZXh0PgogICAgPHRleHQgeD0iMzMwIiB5PSIzMjAiPlszMDAwLDUwMDApPC90ZXh0PgogIDwvZz4KICA8cmVjdCB4PSI0NTAiIHk9IjMwOCIgd2lkdGg9Ijg2IiBoZWlnaHQ9IjE4IiByeD0iMyIgZmlsbD0iIzNmMjUzMCIvPgogIDx0ZXh0IHg9IjQ1NiIgeT0iMzIxIiBmaWxsPSIjZmNhNWE1IiBmb250LXNpemU9IjEyIiBmb250LWZhbWlseT0ibW9ub3NwYWNlIj5bNTAwMCziiJ4pPC90ZXh0PgoKICA8IS0tIHNoYXJlZCBzdHJpbmcgLS0+CiAgPHJlY3QgeD0iODgwIiB5PSIxMTIiIHdpZHRoPSIyNzIiIGhlaWdodD0iMjE2IiByeD0iOCIgZmlsbD0iIzFlMjkzYiIgc3Ryb2tlPSIjNTA0NmU1IiBzdHJva2Utd2lkdGg9IjEuNSIvPgogIDx0ZXh0IHg9IjEwMTYiIHk9IjE0MiIgZmlsbD0iIzhiOGZmNSIgZm9udC1zaXplPSIxNCIgZm9udC13ZWlnaHQ9IjcwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+c2hhcmVkIGJ5IGFsbCB0aHJlZTwvdGV4dD4KICA8dGV4dCB4PSIxMDE2IiB5PSIxODIiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTkiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIHRleHQtYW5jaG9yPSJtaWRkbGUiPls1MDAsMTAwMCk8L3RleHQ+CiAgPHRleHQgeD0iMTAxNiIgeT0iMjE2IiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5UaGUgb25lIGludGVydmFsIHN0cmluZyB0aGF0PC90ZXh0PgogIDx0ZXh0IHg9IjEwMTYiIHk9IjIzNCIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9Im1pZGRsZSI+Y2Fubm90IHRlbGwgeW91IHdoaWNoIHNjaGVtZTwvdGV4dD4KICA8dGV4dCB4PSIxMDE2IiB5PSIyNTIiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTMiIHRleHQtYW5jaG9yPSJtaWRkbGUiPnlvdSBhcmUgbG9va2luZyBhdC48L3RleHQ+CiAgPHRleHQgeD0iMTAxNiIgeT0iMjg4IiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEyIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5ObyBsZSBsYWJlbCBvbiBhbnkgb2YgdGhlbSw8L3RleHQ+CiAgPHRleHQgeD0iMTAxNiIgeT0iMzA2IiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEyIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5zbyBoaXN0b2dyYW1fcXVhbnRpbGUgaXMgb3V0LjwvdGV4dD4KCiAgPHRleHQgeD0iNDgiIHk9IjM0NCIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMiI+RWFjaCByb3cgb21pdHMgdGhlIHNoYXJlZCBbNTAwLDEwMDApIGJ1Y2tldCwgc2hvd24gb25jZSBhdCByaWdodC4gQ291bnRpbmcgaXQgYmFjayBpbiBnaXZlcyB0aGUgMTAsIDcgYW5kIDggYnVja2V0cyBlYWNoIHNjaGVtZSBob2xkcy48L3RleHQ+CgogIDwhLS0gdGhlIHR3byB0cmFwcyAtLT4KICA8bGluZSB4MT0iNDgiIHkxPSIzNTYiIHgyPSIxMTUyIiB5Mj0iMzU2IiBzdHJva2U9IiMzMzQxNTUiIHN0cm9rZS13aWR0aD0iMSIvPgoKICA8cmVjdCB4PSI0OCIgeT0iMzcyIiB3aWR0aD0iNTQwIiBoZWlnaHQ9IjEwNiIgcng9IjgiIGZpbGw9IiMxZTI5M2IiIHN0cm9rZT0iIzNmMjUzMCIgc3Ryb2tlLXdpZHRoPSIxIi8+CiAgPHRleHQgeD0iNzAiIHk9IjM5OCIgZmlsbD0iI2ZjYTVhNSIgZm9udC1zaXplPSIxNSIgZm9udC13ZWlnaHQ9IjcwMCI+U3VtIHdpdGhvdXQgYSBzdGFnZSBmaWx0ZXIgYW5kIHlvdSBpbmZsYXRlIGJ5IDExPC90ZXh0PgogIDx0ZXh0IHg9IjcwIiB5PSI0MjIiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTMiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiPnN1bSBieSAoaW50ZXJ2YWwpIChiZWFjb25fYmxvY2tfaW1wb3J0X2RlbGF5Xy4uLik8L3RleHQ+CiAgPHRleHQgeD0iNzAiIHk9IjQ0NiIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxMyI+MjM2LDMyNCBvYnNlcnZhdGlvbnMgZm9yIDIxLDQ3NiBibG9ja3MsIGJpbnMgb3ZlcmxhcHBpbmcuPC90ZXh0PgogIDx0ZXh0IHg9IjcwIiB5PSI0NjYiIGZpbGw9IiNmYjkyM2MiIGZvbnQtc2l6ZT0iMTMiIGZvbnQtd2VpZ2h0PSI2MDAiPk1lZGlhbiByZWFkcyBhYm91dCAyNSBtcy4gVGhlIHRydXRoIGlzIDEsNTAwIHRvIDIsMDAwIG1zLjwvdGV4dD4KCiAgPHJlY3QgeD0iNjEyIiB5PSIzNzIiIHdpZHRoPSI1NDAiIGhlaWdodD0iMTA2IiByeD0iOCIgZmlsbD0iIzFlMjkzYiIgc3Ryb2tlPSIjM2YyNTMwIiBzdHJva2Utd2lkdGg9IjEiLz4KICA8dGV4dCB4PSI2MzQiIHk9IjM5OCIgZmlsbD0iI2ZjYTVhNSIgZm9udC1zaXplPSIxNSIgZm9udC13ZWlnaHQ9IjcwMCI+VGhlIHRvcCBidWNrZXQgaXMgc3BlbGxlZCB3aXRoIFUrMjIxRTwvdGV4dD4KICA8dGV4dCB4PSI2MzQiIHk9IjQyNCIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxMyIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSI+aW50ZXJ2YWw9IlsxMjAwMCxpbmYpIiAg4oaSICAwIHNlcmllcywgbm8gZXJyb3I8L3RleHQ+CiAgPHRleHQgeD0iNjM0IiB5PSI0NDgiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTMiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiPmludGVydmFsPSJbMTIwMDAs4oieKSIgICAg4oaSICB0aGUgc2xvdyB0YWlsPC90ZXh0PgogIDx0ZXh0IHg9IjYzNCIgeT0iNDY4IiBmaWxsPSIjZmI5MjNjIiBmb250LXNpemU9IjEzIiBmb250LXdlaWdodD0iNjAwIj5UaGUgZmlyc3Qgb25lIHByZXNlbnRzIG9uIGEgZGFzaGJvYXJkIGFzIG5vIHNsb3cgYmxvY2tzLjwvdGV4dD4KCiAgPHRleHQgeD0iNDgiIHk9IjUxMiIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMiI+VGVrdSAyNi43LjEgb24gTkRDMi4gQXQgc3RhZ2U9InRvdGFsX3Byb2Nlc3NpbmdfdGltZSIgdGhlIHNjaGVtZSBmbGlwcyB0byBmaW5lIHdoZW4gcmVzdWx0PSJ1bmtub3duX3BhcmVudCIsIHNvIGl0IGlzIHRoZSBzdGFnZSBhbmQgcmVzdWx0IHBhaXIgdGhhdCBkZWNpZGVzLCBub3QgZWl0aGVyIGxhYmVsIGFsb25lLjwvdGV4dD4KICA8dGV4dCB4PSIxMTUyIiB5PSI1MTIiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiIHRleHQtYW5jaG9yPSJlbmQiPmRvY3Muc3RlcmV1bWxhYnMuY29tPC90ZXh0Pgo8L3N2Zz4K" width="1200" height="540" class="img_ev3q"></p>
<p><strong>One: there are three schemes, not one.</strong> <code>arrival</code> and <code>total_processing_time</code> use a ten-bucket coarse scheme running to <code>[12000,∞)</code>. The other nine stages use a seven-bucket fine scheme running to <code>[2000,∞)</code>. <code>beacon_engine_requests_total</code> uses a third, eight-bucket scheme running to <code>[5000,∞)</code>. The single interval string common to all three is <code>[500,1000)</code>, which makes it useless for telling them apart. There is one further wrinkle: at <code>stage="total_processing_time"</code> the scheme flips to fine when <code>result="unknown_parent"</code>, so the scheme is a function of the stage and result pair rather than of either label alone.</p>
<p><strong>Two: summing without a stage filter inflates elevenfold.</strong> Write <code>sum by (interval) (beacon_block_import_delay_counter_total{...})</code> and you pool all eleven stages into one pseudo-histogram whose bins overlap. For the Geth pairing that totals 236,324 observations against 21,476 blocks. Because the fine scheme's <code>[0,50)</code> bin then holds 71.4% of everything, a median read off that chart lands around 25 ms. The true block-arrival median is in the 1,500-to-2,000 ms bucket. The chart is wrong by a factor of about seventy and looks entirely plausible.</p>
<p><strong>Three: the top bucket is spelled with U+221E.</strong> It renders as <code>[12000,∞)</code>, <code>[2000,∞)</code> and <code>[5000,∞)</code>. A selector written <code>interval="[12000,inf)"</code> matches zero series and returns no error. Every slow block silently vanishes from the result, which presents as a clean tail.</p>
<p>One more trap, this one about method rather than about Teku. Establishing that these buckets are disjoint rather than cumulative cannot be done on one client. Reth's <code>newPayload</code> distribution falls monotonically across all eight bins, which is the exact signature a cumulative scheme produces. Tested on Reth alone the answer comes out backwards. It is Besu, Erigon and Geth, whose distributions rise to an interior mode before falling away, that settle it. Ethrex and Nethermind peak in the first bin like Reth, and give themselves away only later, with a step back up that no cumulative scheme can produce.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-to-measure-on-your-own-teku-nodes">What to measure on your own Teku nodes<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-teku#what-to-measure-on-your-own-teku-nodes" class="hash-link" aria-label="Direct link to What to measure on your own Teku nodes" title="Direct link to What to measure on your own Teku nodes" translate="no">​</a></h2>
<ul>
<li class=""><strong>Alert on <code>beacon_node_syncing_active</code>, then read the logs to attribute the cause.</strong> Held at 1 for five minutes, this gauge fired on the Reth host and nowhere else in the window; there it read 1 at every scrape for three days, while every block-import and engine counter Teku publishes looked healthy or better than healthy. The gauge tells you the beacon node is behind, not why. For the why, grep Teku's log for <code>Waiting for execution layer sync</code>, then check that the execution client is committing blocks, which for Reth means <code>Canonical chain committed</code>. Run both checks rather than either one: in this window they disagreed in both directions, with the gauge reaching 1 on the Ethrex pairing where the Teku log line never appeared, and the log line appearing twice on the Besu pairing where the gauge never left 0.</li>
<li class=""><strong>Always filter by <code>stage</code> before touching <code>interval</code>.</strong> Without it the counts are eleven times too large and the bins overlap. Add <code>result="success"</code> too unless you want <code>unknown_parent</code> injecting six foreign bucket strings into a ten-bucket histogram.</li>
<li class=""><strong>Match the infinity bucket on <code>∞</code>, not on <code>inf</code>.</strong> If a panel shows no blocks in the slowest bucket, check the selector before you believe it.</li>
<li class=""><strong>Read <code>processed</code> and <code>execution_payload_result_received</code> separately.</strong> The first is Teku's own cost and barely moves; the second is the execution client's and moves by nearly five times. Charting only <code>total_processing_time</code> blends them.</li>
<li class=""><strong>Do not expect quantiles.</strong> There is no <code>le</code> label, so <code>histogram_quantile</code> returns nothing. Bucket-bounded statements are the honest ceiling here: a modal bucket or a share above a threshold, not a median in milliseconds.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="coming-next-in-the-series">Coming next in the series<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-teku#coming-next-in-the-series" class="hash-link" aria-label="Direct link to Coming next in the series" title="Direct link to Coming next in the series" translate="no">​</a></h2>
<p>Lodestar is the last client, and on surface area it is the opposite of Teku: 1,184 metric names and 162 genuine histograms against Teku's 410 and 6. Then the finale, where all six clients and their instruments go side by side, with an honest list of the claims from earlier editions that did not survive being measured a second way.</p>
<p>This edition adds one entry to that list, and it is ours. Between drafting and publishing, the Reth pairing was going to be reported as this series' first fully-synced Reth comparison on the strength of five metrics that all said so. The log said otherwise. Across five editions the pattern has held without exception: a client comparison is only as good as the instrument you read it through, and the failure mode is never an error message. It is a plausible number. Catching those is what StereumLabs AI does on our fleet, on <a class="" href="https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack">the measurement stack we described here</a>. If you run Ethereum infrastructure and want this lens on your own nodes, reach us at <a href="https://stereumlabs.com/" target="_blank" rel="noopener noreferrer" class="">stereumlabs.com</a> or <a href="mailto:contact@stereumlabs.com" target="_blank" rel="noopener noreferrer" class="">contact@stereumlabs.com</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="methodology">Methodology<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-teku#methodology" class="hash-link" aria-label="Direct link to Methodology" title="Direct link to Methodology" translate="no">​</a></h2>
<p>Numbers come from Teku's and the execution clients' own metrics on our NDC2 deployment (Vienna), queried on the <code>Prometheus-cold</code> datasource (uid <code>aez9ck4wz05q8e</code>), with the fleet labels documented in <a class="" href="https://docs.stereumlabs.com/docs/dashboards/build-your-own">build your own dashboards</a>. The window is 2026-08-03T00:00:00Z to 2026-08-06T00:00:00Z. Counts are exact counter deltas, <code>M - M offset 3d</code> evaluated at the closing anchor, rather than <code>increase(...[3d])</code>, which extrapolates and returns fractional values. The two agree to within 0.05%. NDC2 runs a six-by-six matrix of consensus and execution clients on identical 12-core bare-metal hosts, so each execution client appears six times, once per consensus-client pairing; every figure here is the Teku pairing specifically.</p>
<ul>
<li class=""><strong>Chain progress.</strong> The chain produced 21,531 blocks in the window's 21,600 slots, height 25,670,639 to 25,692,170. Four execution clients agree on both endpoints to within one block via <code>chain_head_block</code> (Geth), <code>ethereum_blockchain_height</code> (Nethermind, Besu) and <code>head_height</code> (Ethrex), the one-block spread being scrape timing rather than disagreement. Erigon publishes no head-height metric name at all; its head is the label value <code>sync{stage="finish"}</code>, which is a further instance of the part-four lesson that capability hides in labels.</li>
<li class=""><strong>The stage decomposition</strong> is <code>beacon_block_import_delay_counter_total{result="success"}</code> grouped by <code>stage</code> and <code>interval</code>. Per-pairing import totals are Besu 21,465, Erigon 21,465, Ethrex 21,056, Geth 21,476, Nethermind 21,487. All eleven stages report identical counts within a pairing. The buckets are disjoint, established four ways: fine-scheme and coarse-scheme stages sum to bit-identical totals; those totals equal roughly one increment per block; a cumulative-from-below scheme would require the lowest bin to be the maximum, which fails for Besu, Geth and Erigon; and a cumulative <code>le</code>-style scheme would require the top bin to be the maximum, which fails everywhere. <code>beacon_block_import_delay_latest</code> also exists, per stage, but it is a gauge of the most recent block only.</li>
<li class=""><strong>Engine-call figures</strong> are <code>beacon_engine_requests_total</code> grouped by <code>method</code>, <code>interval</code> and <code>outcome</code>, one uniform eight-bucket scheme across all five methods and both outcomes. Successful <code>newPayload</code> totals per pairing run from 21,668 to 22,088 against 21,531 blocks, slightly above one per block. The 40 errors quoted are <code>newPayload</code> only and exclude Reth's zero; Reth logged 11 engine errors on other methods, and Geth is the fleet minimum on engine errors overall with 4.</li>
<li class=""><strong>Metric surface area per consensus client</strong>, anchor-evaluated as distinct metric names and <code>_bucket</code> metric names: Lodestar 1,184 / 162, Lighthouse 781 / 144, Prysm 590 / 65, Nimbus 531 / 25, Teku 410 / 6, Grandine 332 / 71. Teku is not the smallest surface; it is the histogram outlier.</li>
<li class=""><strong>Sync was verified from container logs, not metrics.</strong> Geth logged <code>Chain head was updated</code> 21,555 times, from block 25,670,641 to 25,692,172. Nethermind logged <code>Finished pre-warming caches for block</code> 21,549 times, ending at 25,692,172. Besu logged <code>new added block 25692172</code>. Erigon logs a head update roughly every nine minutes rather than per block; its last one in the window reads <code>head updated number=25692010 age=3s</code>, and its Prometheus head stood at 25,692,169. Ethrex ran from block 25,670,642 to 25,692,172. Teku's <code>Waiting for execution layer sync</code> line appeared 0 times for Geth and Ethrex, 2 for Besu, 11 for Nethermind, 65 for Erigon and 21,600 for Reth. Teku's <code>beacon_node_syncing_active</code> gauge, scraped 4,320 times per host, summed to 4,320 on Reth, 5 on Erigon, 4 on Ethrex, 2 on Nethermind and 0 on Besu and Geth.</li>
<li class=""><strong>Reth's exclusion.</strong> <code>Canonical chain committed</code> appears zero times on the Teku-paired Reth host across the window, against 6,452 occurrences on the Lighthouse-paired host running the same build over the same window. Its pipeline advanced from <code>pipeline_stages=4/14 stage=Execution</code> to <code>pipeline_stages=9/14 stage=MerkleExecute</code> with target 25,588,987. We did not confirm from Teku's source that optimistic import is what produces the <code>success</code> result on that pairing; the specification permits it, the log states the node was waiting on the execution layer, and the counter recorded successes, but the causal link is our reading rather than a measurement. Separately, <code>reth_blockchain_tree_canonical_chain_height</code> reads 0 on all six Reth hosts for the first two days of the window, so it is unusable as a sync indicator in either direction.</li>
<li class=""><strong>The Ethrex shortfall.</strong> Ethrex imported 21,056 blocks against a chain that produced 21,531, and its own log shows 21,104 prewarm passes, so both instruments agree the pair observed roughly 450 fewer blocks. The deficit concentrates in three hours (109, 190 and 159 blocks against a normal 300 per hour) with no errors and no restart in the log. Teku's <code>beacon_node_syncing_active</code> on that host reached 1 in two of those three hours and in no other hour of the window, which narrows when the deficit accrued without establishing its cause. Ethrex was at the chain tip at both window ends. Every Ethrex percentage here therefore rests on a denominator about 2% smaller than its peers, which does not change its rank on any measure reported above but is worth knowing.</li>
<li class=""><strong>Our fleet runs no live validators.</strong> It receives mirrored validator-client traffic, unchanged across this window.</li>
</ul>]]></content:encoded>
            <category>client comparison</category>
            <category>validator duties</category>
            <category>observability</category>
            <category>engine API</category>
            <category>Teku</category>
            <category>Reth</category>
            <category>Geth</category>
            <category>Nethermind</category>
            <category>Besu</category>
            <category>Erigon</category>
            <category>Ethrex</category>
            <category>StereumLabs AI</category>
        </item>
        <item>
            <title><![CDATA[Where the slot goes: Grandine, and the metrics a name search cannot find]]></title>
            <link>https://docs.stereumlabs.com/blog/where-the-slot-goes-grandine</link>
            <guid>https://docs.stereumlabs.com/blog/where-the-slot-goes-grandine</guid>
            <pubDate>Wed, 05 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Grandine hides its engine-call timing behind a metric name no keyword search reaches. Besu's slow head update is confirmed on a fourth instrument.]]></description>
            <content:encoded><![CDATA[<p>This edition was nearly published with its central claim inverted. We ran three Prometheus metric-name searches against Grandine, across eleven substrings including payload, forkchoice, engine, execution, latency, delay and duration. The first returned nothing, the second two histograms and the third eleven, and not one of them was the engine-call timing we were looking for. The obvious conclusion was that Grandine is the sparse end of this series: a client that times block arrival and blob fetches and nothing else. A fact-check caught it before publication.</p>
<p>Grandine times both engine calls, per method, at more than one observation per slot. The metric is called <code>ETH1_API_REQUEST_TIMES</code>. It is in capitals, it contains none of the eleven substrings we searched for, and the engine method lives in a label rather than the name, so <code>method="engine_newPayloadV4"</code> sits inside a series whose name says only that some eth1 API was called. No name search reaches it.</p>
<p>Grandine is not the sparse end of this series, and it is not the rich end either: an inventory of its scrape job returns 70 histograms against Lodestar's 158 and Lighthouse's 143, and on total metric names it is the sparsest of the six at 330. The point is not where it ranks. The point is that a comparatively modest client still hid a per-method engine timer from three searches, which means the search was the problem, not the client.</p>
<p>What the metric shows once you find it: Besu's head-update call costs 162 ms against 4 to 7 ms for every other execution client, which is the fourth independent instrument to say so, and the middle of the execution-client field reorders again.</p>
<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>Read this first</div><div class="admonitionContent_BuS1"><ul>
<li class=""><strong>We got this wrong first, and the mechanism matters.</strong> A name-pattern search cannot establish that a client lacks instrumentation. <code>ETH1_API_REQUEST_TIMES</code> is all-caps, carries the engine method in a <code>method</code> label, and matches none of the substrings you would think to grep for. The reliable form is an inventory per scrape job, <code>count by (__name__) ({job="grandine"})</code>, and then reading labels. We now do that first, and the finale of this series will re-derive every "client X instruments Y" statement in earlier editions the same way.</li>
<li class=""><strong>Two of Grandine's histograms use default Prometheus buckets, and that limits them.</strong> Both the arrival histogram and <code>ETH1_API_REQUEST_TIMES</code> step 1 s, 2.5 s, 5 s, 10 s at the top. Neither has a boundary at the 4-second attestation deadline, and for <code>forkchoiceUpdated</code> values of 4 to 7 ms the bottom buckets at 5 and 10 ms are coarser than the quantity being measured. We quote means where the buckets cannot support quantiles, and say which is which.</li>
<li class=""><strong>We are not quoting a cross-client arrival spread from Grandine.</strong> Its arrival histogram puts 77.6 to 78.3% of observations at or below 2.5 s, so an interpolated median lands inside a bucket holding three quarters of the data. The nine milliseconds separating the five pairings is arithmetic on bucket occupancy, not a timing measurement, and we say so rather than adding it to this series' arrival control.</li>
<li class=""><strong>Reth is excluded, for the fourth edition running,</strong> and Grandine's own counters show why more sharply than before: it logged 86,350 <code>newPayload</code> calls for the Reth pairing against about 22,000 for the other five, on a chain that produced 21,521 blocks in the window. Repeated re-delivery to a node that never returns <code>VALID</code> is what that looks like. Its 34 ms mean is a <code>SYNCING</code> artifact.</li>
<li class=""><strong>Window and versions.</strong> Three days, 2026-07-27 to 2026-07-30, on Grandine 2.0.5 paired with Geth v1.17.4, Nethermind 1.39.2, Besu 26.7.0, Erigon v3.5.2 and Ethrex 22.0.0, on NDC2 bare metal in Vienna. No execution-client version changed inside the window; the last bump was 2026-07-23. Every execution client was confirmed at the chain tip from its own container log at both ends. This window begins where <a class="" href="https://docs.stereumlabs.com/blog/where-the-slot-goes-prysm">part three's</a> ended.</li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-metric-a-keyword-search-cannot-find">The metric a keyword search cannot find<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-grandine#the-metric-a-keyword-search-cannot-find" class="hash-link" aria-label="Direct link to The metric a keyword search cannot find" title="Direct link to The metric a keyword search cannot find" translate="no">​</a></h2>
<p>Here is what the three failed searches looked for, against what the job publishes:</p>
<p><img decoding="async" loading="lazy" alt="How the metric was missed: three name searches for payload, forkchoice, engine, execution, latency, delay and duration return nothing, while an inventory of the grandine job returns 70 histograms including ETH1_API_REQUEST_TIMES with engine method labels" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDUwMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNTAwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTIiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjciIGZvbnQtd2VpZ2h0PSI3MDAiPkhvdyB3ZSBuZWFybHkgcHVibGlzaGVkIHRoZSBvcHBvc2l0ZTwvdGV4dD4KICA8dGV4dCB4PSI0OCIgeT0iODIiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTYiPnRocmVlIG1ldHJpYy1uYW1lIHNlYXJjaGVzIGFnYWluc3QgR3JhbmRpbmUsIHRoZW4gYW4gaW52ZW50b3J5IG9mIHRoZSBzYW1lIHNjcmFwZSBqb2I8L3RleHQ+CgogIDwhLS0gc2VhcmNoZXMgLS0+CiAgPHRleHQgeD0iNjAiIHk9IjEyOCIgZmlsbD0iI2ZjYTVhNSIgZm9udC1zaXplPSIxNyIgZm9udC13ZWlnaHQ9IjcwMCI+TmFtZSBzZWFyY2hlczwvdGV4dD4KICA8cmVjdCB4PSI2MCIgeT0iMTQ2IiB3aWR0aD0iNTYwIiBoZWlnaHQ9IjQ2IiByeD0iNiIgZmlsbD0iIzFlMjkzYiIgc3Ryb2tlPSIjM2YyNTMwIiBzdHJva2Utd2lkdGg9IjEiLz4KICA8dGV4dCB4PSI3NiIgeT0iMTY4IiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjEzIiBmb250LWZhbWlseT0ibW9ub3NwYWNlIj4uKihwYXlsb2FkfGZvcmtjaG9pY2V8ZXhlY3V0aW9uKS4qPC90ZXh0PgogIDx0ZXh0IHg9Ijc2IiB5PSIxODYiIGZpbGw9IiNmY2E1YTUiIGZvbnQtc2l6ZT0iMTMiPjAgaGlzdG9ncmFtczwvdGV4dD4KCiAgPHJlY3QgeD0iNjAiIHk9IjIwMCIgd2lkdGg9IjU2MCIgaGVpZ2h0PSI0NiIgcng9IjYiIGZpbGw9IiMxZTI5M2IiIHN0cm9rZT0iIzNmMjUzMCIgc3Ryb2tlLXdpZHRoPSIxIi8+CiAgPHRleHQgeD0iNzYiIHk9IjIyMiIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxMyIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSI+LiooZW5naW5lfGxhdGVuY3l8ZGVsYXl8YXJyaXZhbHxpbXBvcnQpLio8L3RleHQ+CiAgPHRleHQgeD0iNzYiIHk9IjI0MCIgZmlsbD0iI2ZjYTVhNSIgZm9udC1zaXplPSIxMyI+MiBoaXN0b2dyYW1zIMK3IGFycml2YWwgYW5kIHRoZSBibG9iIGZldGNoLCBub3QgdGhlIHBheWxvYWQgY2FsbDwvdGV4dD4KCiAgPHJlY3QgeD0iNjAiIHk9IjI1NCIgd2lkdGg9IjU2MCIgaGVpZ2h0PSI0NiIgcng9IjYiIGZpbGw9IiMxZTI5M2IiIHN0cm9rZT0iIzNmMjUzMCIgc3Ryb2tlLXdpZHRoPSIxIi8+CiAgPHRleHQgeD0iNzYiIHk9IjI3NiIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxMyIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSI+LioobGF0ZW5jeXxkZWxheXxkdXJhdGlvbnxtaWxsaXNlY29uZHN8c2Vjb25kcykuKjwvdGV4dD4KICA8dGV4dCB4PSI3NiIgeT0iMjk0IiBmaWxsPSIjZmNhNWE1IiBmb250LXNpemU9IjEzIj4xMSBoaXN0b2dyYW1zIMK3IG1vc3RseSBQZWVyREFTIHRpbWVycywgc3RpbGwgbm90IHRoZSBwYXlsb2FkIGNhbGw8L3RleHQ+CgogIDx0ZXh0IHg9IjYwIiB5PSIzMzAiIGZpbGw9IiM4ZTliYmQiIGZvbnQtc2l6ZT0iMTQiPkNvbmNsdXNpb24gZHJhd246ICJHcmFuZGluZSB0aW1lcyBubyBlbmdpbmUgY2FsbC4iPC90ZXh0PgogIDx0ZXh0IHg9IjYwIiB5PSIzNTIiIGZpbGw9IiNmY2E1YTUiIGZvbnQtc2l6ZT0iMTQiIGZvbnQtd2VpZ2h0PSI2MDAiPldyb25nLjwvdGV4dD4KCiAgPCEtLSBhcnJvdyAtLT4KICA8bGluZSB4MT0iNjQwIiB5MT0iMjIyIiB4Mj0iNjkwIiB5Mj0iMjIyIiBzdHJva2U9IiM1MDQ2ZTUiIHN0cm9rZS13aWR0aD0iMi41Ii8+CiAgPHBvbHlsaW5lIHBvaW50cz0iNjgyLDIxNSA2OTAsMjIyIDY4MiwyMjkiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzUwNDZlNSIgc3Ryb2tlLXdpZHRoPSIyLjUiLz4KCiAgPCEtLSBpbnZlbnRvcnkgLS0+CiAgPHRleHQgeD0iNzEwIiB5PSIxMjgiIGZpbGw9IiM4NmVmYWMiIGZvbnQtc2l6ZT0iMTciIGZvbnQtd2VpZ2h0PSI3MDAiPkludmVudG9yeTwvdGV4dD4KICA8cmVjdCB4PSI3MTAiIHk9IjE0NiIgd2lkdGg9IjQ0MCIgaGVpZ2h0PSI0NiIgcng9IjYiIGZpbGw9IiMxZTI5M2IiIHN0cm9rZT0iIzJiNGEzNyIgc3Ryb2tlLXdpZHRoPSIxIi8+CiAgPHRleHQgeD0iNzI2IiB5PSIxNjYiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTEiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiPmNvdW50IGJ5IChfX25hbWVfXykgKHs8L3RleHQ+CiAgPHRleHQgeD0iNzI2IiB5PSIxODIiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTEiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiPiAgX19uYW1lX189fiIuK19idWNrZXQiLCBqb2I9ImdyYW5kaW5lIn0pPC90ZXh0PgoKICA8dGV4dCB4PSI3MTAiIHk9IjIzMCIgZmlsbD0iIzIyYzU1ZSIgZm9udC1zaXplPSI0NCIgZm9udC13ZWlnaHQ9IjcwMCI+NzA8L3RleHQ+CiAgPHRleHQgeD0iNzgyIiB5PSIyMzAiIGZpbGw9IiM4NmVmYWMiIGZvbnQtc2l6ZT0iMTciPmhpc3RvZ3JhbXM8L3RleHQ+CgogIDxyZWN0IHg9IjcxMCIgeT0iMjUyIiB3aWR0aD0iNDQwIiBoZWlnaHQ9IjEwMiIgcng9IjYiIGZpbGw9IiMwZjJhMWMiIHN0cm9rZT0iIzJiNGEzNyIgc3Ryb2tlLXdpZHRoPSIxIi8+CiAgPHRleHQgeD0iNzI2IiB5PSIyNzQiIGZpbGw9IiM4NmVmYWMiIGZvbnQtc2l6ZT0iMTMiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiPkVUSDFfQVBJX1JFUVVFU1RfVElNRVM8L3RleHQ+CiAgPHRleHQgeD0iNzI2IiB5PSIyOTYiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTIiPm1ldGhvZD0iZW5naW5lX25ld1BheWxvYWRWNCI8L3RleHQ+CiAgPHRleHQgeD0iNzI2IiB5PSIzMTQiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTIiPm1ldGhvZD0iZW5naW5lX2ZvcmtjaG9pY2VVcGRhdGVkVjMiPC90ZXh0PgogIDx0ZXh0IHg9IjcyNiIgeT0iMzMyIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjEyIj5tZXRob2Q9ImVuZ2luZV9nZXRQYXlsb2FkVjUiIMK3IGdldEJsb2JzVjI8L3RleHQ+CiAgPHRleHQgeD0iNzI2IiB5PSIzNDgiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTEiPnBsdXMgTVVUQVRPUl9CTE9DS19QUk9DRVNTSU5HX1RJTUVTLCBwZXIgc2xvdDwvdGV4dD4KCiAgPHRleHQgeD0iNDgiIHk9IjQwNCIgZmlsbD0iI2ZkZTY4YSIgZm9udC1zaXplPSIxNSI+QWxsLWNhcHMsIGFuZCB0aGUgZW5naW5lIG1ldGhvZCBsaXZlcyBpbiBhIGxhYmVsLiBObyBzdWJzdHJpbmcgc2VhcmNoIGZvciAiZW5naW5lIiBvciAicGF5bG9hZCIgY2FuIHJlYWNoIGl0LjwvdGV4dD4KICA8dGV4dCB4PSI0OCIgeT0iNDMwIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE0Ij5BIG1ldHJpYydzIG5hbWUgdGVsbHMgeW91IHdoYXQgaXRzIGF1dGhvciBjYWxsZWQgaXQsIG5vdCB3aGF0IGl0IG1lYXN1cmVzLiBJbnZlbnRvcnkgdGhlIGpvYiwgdGhlbiByZWFkIHRoZSBsYWJlbHMuPC90ZXh0PgogIDx0ZXh0IHg9IjQ4IiB5PSI0NzAiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiPkdyYW5kaW5lIDIuMC41IG9uIE5EQzIuIFRoZSBzYW1lIGRpc2NpcGxpbmUgaXMgb3dlZCB0byBldmVyeSAiY2xpZW50IFggZG9lcyBub3QgZXhwb3NlIFkiIGNsYWltIGluIHRoaXMgc2VyaWVzLjwvdGV4dD4KICA8dGV4dCB4PSIxMTUyIiB5PSI0NzAiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiIHRleHQtYW5jaG9yPSJlbmQiPmRvY3Muc3RlcmV1bWxhYnMuY29tPC90ZXh0Pgo8L3N2Zz4K" width="1200" height="500" class="img_ev3q"></p>
<table><thead><tr><th>What we searched</th><th>Histograms returned</th><th>Engine-call timing found</th></tr></thead><tbody><tr><td><code>.*(payload|forkchoice|execution).*</code></td><td>0</td><td>no</td></tr><tr><td><code>.*(engine|latency|delay|arrival|import).*</code></td><td>2</td><td>no, the two are block arrival and the blob fetch</td></tr><tr><td><code>.*(latency|delay|duration|milliseconds|seconds).*</code></td><td>11</td><td>no</td></tr><tr><td><code>count by (__name__) ({__name__=~".+_bucket", job="grandine"})</code></td><td><strong>70</strong></td><td><strong>yes</strong></td></tr></tbody></table>
<p>The second search is the instructive one. Searching for <code>engine</code> does return an engine-API histogram, <code>beacon_engine_getBlobsV2_request_duration_seconds</code>, which is how we came to believe Grandine timed the blob fetch and nothing else on that side. The third widens to eleven histograms, mostly PeerDAS and KZG timers, and still misses the payload call. Only the inventory finds it, because <code>ETH1_API_REQUEST_TIMES</code> shares no substring with any word a person would think to type.</p>
<p>It carries <code>method="engine_newPayloadV4"</code>, <code>"engine_forkchoiceUpdatedV3"</code>, <code>"engine_getPayloadV5"</code>, <code>"engine_getBlobsV2"</code> and <code>"engine_exchangeCapabilities"</code>. Alongside it sits <code>MUTATOR_BLOCK_PROCESSING_TIMES</code>, a per-slot consensus-side block-processing timer. Name searches can reach some of what a client publishes; what they cannot do is establish that something is absent.</p>
<p>The generalisable point for anyone auditing their own stack: a metric's name tells you what its author called it, not what it measures. Capability hides in two places a substring search does not reach, unconventional casing and label values, and both appear here at once. Inventory the scrape job, then read the labels.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-grandines-engine-timing-shows">What Grandine's engine timing shows<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-grandine#what-grandines-engine-timing-shows" class="hash-link" aria-label="Direct link to What Grandine's engine timing shows" title="Direct link to What Grandine's engine timing shows" translate="no">​</a></h2>
<p>With the metric located, Grandine answers the question this series has been asking of every client. Over the window, per pairing:</p>
<p><img decoding="async" loading="lazy" alt="newPayload and forkchoiceUpdated latency per execution client under Grandine: newPayload runs from 119 ms for Ethrex to 568 ms for Erigon, while forkchoiceUpdated is 4 to 7 ms for everyone except Besu at 162 ms" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDUyMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNTIwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTIiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjciIGZvbnQtd2VpZ2h0PSI3MDAiPkJvdGggZW5naW5lIGNhbGxzLCBhcyBHcmFuZGluZSB0aW1lcyB0aGVtPC90ZXh0PgogIDx0ZXh0IHg9IjQ4IiB5PSI4MiIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxNiI+RVRIMV9BUElfUkVRVUVTVF9USU1FUyBieSBtZXRob2QgwrcgbWVhbnMgb3ZlciB0aHJlZSBkYXlzIMK3IGFib3V0IDIyLDAwMCBjYWxscyBwZXIgcGFpcmluZzwvdGV4dD4KCiAgPGxpbmUgeDE9IjY0MCIgeTE9IjExMiIgeDI9IjY0MCIgeTI9IjQyMCIgc3Ryb2tlPSIjMWMyNjU0IiBzdHJva2Utd2lkdGg9IjEiLz4KCiAgPHRleHQgeD0iNjAiIHk9IjEzMiIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxOCIgZm9udC13ZWlnaHQ9IjcwMCI+ZW5naW5lX25ld1BheWxvYWRWNDwvdGV4dD4KICA8dGV4dCB4PSI2MCIgeT0iMTUyIiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEzIj50aGUgY2FsbCB0aGF0IGhhbmRzIG92ZXIgdGhlIGJsb2NrPC90ZXh0PgogIDx0ZXh0IHg9IjY3NiIgeT0iMTMyIiBmaWxsPSIjZTJlOGY0IiBmb250LXNpemU9IjE4IiBmb250LXdlaWdodD0iNzAwIj5lbmdpbmVfZm9ya2Nob2ljZVVwZGF0ZWRWMzwvdGV4dD4KICA8dGV4dCB4PSI2NzYiIHk9IjE1MiIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMyI+dGhlIGNhbGwgdGhhdCBuYW1lcyB0aGUgaGVhZDwvdGV4dD4KCiAgPGcgc3Ryb2tlPSIjMTYxZTQ0IiBzdHJva2Utd2lkdGg9IjEiPgogICAgPGxpbmUgeDE9IjYwIiB5MT0iMjAwIiB4Mj0iMTE0MCIgeTI9IjIwMCIvPgogICAgPGxpbmUgeDE9IjYwIiB5MT0iMjQ4IiB4Mj0iMTE0MCIgeTI9IjI0OCIvPgogICAgPGxpbmUgeDE9IjYwIiB5MT0iMjk2IiB4Mj0iMTE0MCIgeTI9IjI5NiIvPgogICAgPGxpbmUgeDE9IjYwIiB5MT0iMzQ0IiB4Mj0iMTE0MCIgeTI9IjM0NCIvPgogICAgPGxpbmUgeDE9IjYwIiB5MT0iMzkyIiB4Mj0iMTE0MCIgeTI9IjM5MiIvPgogIDwvZz4KCiAgPCEtLSBMRUZUOiBuZXdQYXlsb2FkLiB4MD0yMDAsIDAuLjYwMG1zIC0+IDM4MHB4ICgwLjYzMyBweC9tcykgLS0+CiAgPGcgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+CiAgICA8dGV4dCB4PSIyMDAiIHk9IjQxNCI+MDwvdGV4dD48dGV4dCB4PSIzNTgiIHk9IjQxNCI+MjUwIG1zPC90ZXh0Pjx0ZXh0IHg9IjUxNyIgeT0iNDE0Ij41MDAgbXM8L3RleHQ+CiAgPC9nPgogIDx0ZXh0IHg9IjE5MCIgeT0iMjA0IiBmaWxsPSIjODZlZmFjIiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0iZW5kIiBmb250LXdlaWdodD0iNjAwIj5FdGhyZXg8L3RleHQ+CiAgPHJlY3QgeD0iMjAwIiB5PSIxODgiIHdpZHRoPSI3NS4zIiBoZWlnaHQ9IjIyIiByeD0iMyIgZmlsbD0iIzIyYzU1ZSIvPjx0ZXh0IHg9IjI4NSIgeT0iMjA1IiBmaWxsPSIjODZlZmFjIiBmb250LXNpemU9IjEzIj4xMTkgbXM8L3RleHQ+CiAgPHRleHQgeD0iMTkwIiB5PSIyNTIiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJlbmQiPk5ldGhlcm1pbmQ8L3RleHQ+CiAgPHJlY3QgeD0iMjAwIiB5PSIyMzYiIHdpZHRoPSIxNTEuMiIgaGVpZ2h0PSIyMiIgcng9IjMiIGZpbGw9IiM3OThiZmYiLz48dGV4dCB4PSIzNjEiIHk9IjI1MyIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxMyI+MjM5IG1zPC90ZXh0PgogIDx0ZXh0IHg9IjE5MCIgeT0iMzAwIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0iZW5kIj5HZXRoPC90ZXh0PgogIDxyZWN0IHg9IjIwMCIgeT0iMjg0IiB3aWR0aD0iMTc2LjkiIGhlaWdodD0iMjIiIHJ4PSIzIiBmaWxsPSIjNzk4YmZmIi8+PHRleHQgeD0iMzg3IiB5PSIzMDEiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTMiPjI3OSBtczwvdGV4dD4KICA8dGV4dCB4PSIxOTAiIHk9IjM0OCIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9ImVuZCI+QmVzdTwvdGV4dD4KICA8cmVjdCB4PSIyMDAiIHk9IjMzMiIgd2lkdGg9IjIzOC4yIiBoZWlnaHQ9IjIyIiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPjx0ZXh0IHg9IjQ0OCIgeT0iMzQ5IiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjEzIj4zNzYgbXM8L3RleHQ+CiAgPHRleHQgeD0iMTkwIiB5PSIzOTYiIGZpbGw9IiNmYjkyM2MiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI2MDAiPkVyaWdvbjwvdGV4dD4KICA8cmVjdCB4PSIyMDAiIHk9IjM4MCIgd2lkdGg9IjM1OS41IiBoZWlnaHQ9IjIyIiByeD0iMyIgZmlsbD0iI2Y5NzMxNiIvPjx0ZXh0IHg9IjU2OSIgeT0iMzk3IiBmaWxsPSIjZmI5MjNjIiBmb250LXNpemU9IjEzIj41NjggbXM8L3RleHQ+CgogIDwhLS0gUklHSFQ6IEZDVS4geDA9NzQwLCAwLi4xNzBtcyAtPiAzNDBweCAoMi4wIHB4L21zKSAtLT4KICA8ZyBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEyIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj4KICAgIDx0ZXh0IHg9Ijc0MCIgeT0iNDE0Ij4wPC90ZXh0Pjx0ZXh0IHg9Ijg0MCIgeT0iNDE0Ij41MCBtczwvdGV4dD48dGV4dCB4PSI5NDAiIHk9IjQxNCI+MTAwIG1zPC90ZXh0Pjx0ZXh0IHg9IjEwNDAiIHk9IjQxNCI+MTUwIG1zPC90ZXh0PgogIDwvZz4KICA8dGV4dCB4PSI3MzAiIHk9IjIwNCIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9ImVuZCI+RXRocmV4PC90ZXh0PgogIDxyZWN0IHg9Ijc0MCIgeT0iMTg4IiB3aWR0aD0iMTMuOCIgaGVpZ2h0PSIyMiIgcng9IjMiIGZpbGw9IiM3OThiZmYiLz48dGV4dCB4PSI3NjIiIHk9IjIwNSIgZmlsbD0iIzhlOWJiZCIgZm9udC1zaXplPSIxMyI+Ni45PC90ZXh0PgogIDx0ZXh0IHg9IjczMCIgeT0iMjUyIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0iZW5kIj5OZXRoZXJtaW5kPC90ZXh0PgogIDxyZWN0IHg9Ijc0MCIgeT0iMjM2IiB3aWR0aD0iOC42IiBoZWlnaHQ9IjIyIiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPjx0ZXh0IHg9Ijc1NyIgeT0iMjUzIiBmaWxsPSIjOGU5YmJkIiBmb250LXNpemU9IjEzIj40LjM8L3RleHQ+CiAgPHRleHQgeD0iNzMwIiB5PSIzMDAiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJlbmQiPkdldGg8L3RleHQ+CiAgPHJlY3QgeD0iNzQwIiB5PSIyODQiIHdpZHRoPSIxNC44IiBoZWlnaHQ9IjIyIiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPjx0ZXh0IHg9Ijc2MyIgeT0iMzAxIiBmaWxsPSIjOGU5YmJkIiBmb250LXNpemU9IjEzIj43LjQ8L3RleHQ+CiAgPHRleHQgeD0iNzMwIiB5PSIzNDgiIGZpbGw9IiNmYjkyM2MiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI3MDAiPkJlc3U8L3RleHQ+CiAgPHJlY3QgeD0iNzQwIiB5PSIzMzIiIHdpZHRoPSIzMjMuNCIgaGVpZ2h0PSIyMiIgcng9IjMiIGZpbGw9IiNmOTczMTYiLz48dGV4dCB4PSIxMDU1IiB5PSIzNDkiIGZpbGw9IiMwZTE1MzAiIGZvbnQtc2l6ZT0iMTMiIGZvbnQtd2VpZ2h0PSI3MDAiIHRleHQtYW5jaG9yPSJlbmQiPjE2MiBtczwvdGV4dD4KICA8dGV4dCB4PSI3MzAiIHk9IjM5NiIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9ImVuZCI+RXJpZ29uPC90ZXh0PgogIDxyZWN0IHg9Ijc0MCIgeT0iMzgwIiB3aWR0aD0iMTEuMiIgaGVpZ2h0PSIyMiIgcng9IjMiIGZpbGw9IiM3OThiZmYiLz48dGV4dCB4PSI3NjAiIHk9IjM5NyIgZmlsbD0iIzhlOWJiZCIgZm9udC1zaXplPSIxMyI+NS42PC90ZXh0PgoKICA8dGV4dCB4PSI0OCIgeT0iNDUyIiBmaWxsPSIjZmRlNjhhIiBmb250LXNpemU9IjE1Ij5CZXN1IHNwZW5kcyAyMiB0byAzNyB0aW1lcyBpdHMgcGVlcnMgb24gdGhlIGhlYWQtdXBkYXRlIGNhbGwgaGVyZS4gRm91ciBjb25zZW5zdXMgY2xpZW50cyBtZWFzdXJlIGl0cyAxNjIgdG8gMjAwIG1zOyB0aHJlZSBvZiB0aGUgZm91ciBhbHNvIHNlZSBhIGdhcCB0aGlzIHdpZGUuPC90ZXh0PgogIDx0ZXh0IHg9IjQ4IiB5PSI0NzYiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTQiPk9uIG5ld1BheWxvYWQsIE5ldGhlcm1pbmQgaXMgYWhlYWQgb2YgR2V0aCBoZXJlIHdoZXJlIFByeXNtIGhhZCBHZXRoIGFoZWFkOiB0aGUgbWlkZGxlIG9mIHRoZSBmaWVsZCBzdGlsbCBkb2VzIG5vdCByYW5rIGFjcm9zcyBwYWlyaW5ncy48L3RleHQ+CiAgPHRleHQgeD0iNDgiIHk9IjUwMiIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMiI+TWVhbnMgYXJlIGV4YWN0OyB0aGUgaGlzdG9ncmFtJ3MgZGVmYXVsdCBidWNrZXRzIGFyZSB0b28gY29hcnNlIGZvciBmb3JrY2hvaWNlVXBkYXRlZCBxdWFudGlsZXMsIHNvIG5vIHBlcmNlbnRpbGVzIGFyZSBxdW90ZWQgZm9yIGl0LiBSZXRoIGV4Y2x1ZGVkIChtaWQgc3RhZ2VkLXN5bmMpLjwvdGV4dD4KICA8dGV4dCB4PSIxMTUyIiB5PSI1MDIiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiIHRleHQtYW5jaG9yPSJlbmQiPmRvY3Muc3RlcmV1bWxhYnMuY29tPC90ZXh0Pgo8L3N2Zz4K" width="1200" height="520" class="img_ev3q"></p>
<table><thead><tr><th>Execution client</th><th><code>newPayload</code> mean</th><th><code>newPayload</code> 90th pct</th><th><code>forkchoiceUpdated</code> mean</th></tr></thead><tbody><tr><td><strong>Ethrex</strong> 22.0.0</td><td>119 ms</td><td>168 ms</td><td>6.9 ms</td></tr><tr><td><strong>Nethermind</strong> 1.39.2</td><td>239 ms</td><td>501 ms</td><td>4.3 ms</td></tr><tr><td><strong>Geth</strong> v1.17.4</td><td>279 ms</td><td>492 ms</td><td>7.4 ms</td></tr><tr><td><strong>Besu</strong> 26.7.0</td><td>376 ms</td><td>764 ms</td><td><strong>162 ms</strong></td></tr><tr><td><strong>Erigon</strong> v3.5.2</td><td>568 ms</td><td>1,147 ms</td><td>5.6 ms</td></tr></tbody></table>
<p>Two things carry over from earlier editions and one is new.</p>
<p>Carrying over: Ethrex fastest and Erigon slowest on <code>newPayload</code>, which now holds under four consensus clients. And the middle reorders again, with Nethermind ahead of Geth here where Prysm had Geth ahead of Nethermind, which is <a class="" href="https://docs.stereumlabs.com/blog/where-the-slot-goes-prysm">part three's</a> finding that the middle of the field does not rank across pairings, arriving on schedule with a fourth instrument.</p>
<p>New, and worth its own section: Besu's head-update call.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="besus-head-update-now-on-four-instruments">Besu's head update, now on four instruments<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-grandine#besus-head-update-now-on-four-instruments" class="hash-link" aria-label="Direct link to Besu's head update, now on four instruments" title="Direct link to Besu's head update, now on four instruments" translate="no">​</a></h2>
<p><code>forkchoiceUpdated</code> is the engine call almost no dashboard shows. Four consensus clients on our fleet time it, on four separate sets of execution-client hosts, and they agree:</p>
<table><thead><tr><th>Instrument</th><th>Besu</th><th>Everyone else</th><th>Besu's multiple</th></tr></thead><tbody><tr><td>Lighthouse</td><td>187 ms</td><td>5.8 to 14.5 ms</td><td>13x to 32x</td></tr><tr><td>Nimbus</td><td>187 ms</td><td>63 to 262 ms</td><td>0.7x to 3.0x</td></tr><tr><td>Prysm</td><td>200 ms</td><td>4.3 to 9.9 ms</td><td>20x to 46x</td></tr><tr><td><strong>Grandine</strong></td><td><strong>162 ms</strong></td><td><strong>4.3 to 7.4 ms</strong></td><td><strong>22x to 37x</strong></td></tr></tbody></table>
<p>All four rows are the same three days, 2026-07-27 to 07-30, so nothing here is being compared across windows.</p>
<p>Besu's own figure is the stable one: 162 to 200 ms on four instruments and four sets of hosts, at roughly 22,000 calls each. The gap to its peers is not equally stable. On three of the four instruments Besu costs 13 to 46 times what the other execution clients cost, and on Nimbus it does not, because under Nimbus both Ethrex and Nethermind also read in the hundreds of milliseconds, which no other instrument reproduces. So four instruments carry the magnitude and three carry the gap. Even at three, it is the most reproducible client-specific result in this series. The mechanism remains bounded but unproven, and the <a class="" href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour">pruning census</a> is where the plausible cause sits, since that is where Besu was found doing storage work on the engine-API hot path.</p>
<p>We also repeat the limit stated in part three: this cost is not attestation budget. <code>forkchoiceUpdated</code> does not sit between a block arriving and the block becoming attestable. It is engine-layer work your node pays for and your dashboard probably does not show you.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-arrival-histogram-and-the-number-we-are-not-quoting">The arrival histogram, and the number we are not quoting<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-grandine#the-arrival-histogram-and-the-number-we-are-not-quoting" class="hash-link" aria-label="Direct link to The arrival histogram, and the number we are not quoting" title="Direct link to The arrival histogram, and the number we are not quoting" translate="no">​</a></h2>
<p>Grandine's arrival histogram, <code>beacon_block_gossip_slot_start_delay_time</code>, recorded 21,596 to 21,717 observations per pairing against the 21,521 blocks these 21,600 slots produced. It counts gossip block receptions, not slots, so the surplus of 75 to 196 is a node hearing some blocks more than once and the total cannot tell you that every slot is represented. It also contains a trap worth more attention than the numbers it yields:</p>
<p><img decoding="async" loading="lazy" alt="Grandine&amp;#39;s arrival histogram read two ways: the median sits near 1.94 seconds for every pairing while the mean of the same data runs from 8.8 to 19.9 seconds, because under one percent of observations exceed the top ten second bucket" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDUwMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNTAwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTIiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjciIGZvbnQtd2VpZ2h0PSI3MDAiPk9uZSBoaXN0b2dyYW0sIHR3byByZWFkaW5ncywgdGVuIHRpbWVzIGFwYXJ0PC90ZXh0PgogIDx0ZXh0IHg9IjQ4IiB5PSI4MiIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxNiI+R3JhbmRpbmUncyBibG9jay1hcnJpdmFsIGhpc3RvZ3JhbSDCtyBzYW1lIG1ldHJpYywgc2FtZSB3aW5kb3csIDIxLDU5NiB0byAyMSw3MTcgb2JzZXJ2YXRpb25zIHBlciBwYWlyaW5nPC90ZXh0PgoKICA8bGluZSB4MT0iNjAwIiB5MT0iMTEyIiB4Mj0iNjAwIiB5Mj0iNDE4IiBzdHJva2U9IiMxYzI2NTQiIHN0cm9rZS13aWR0aD0iMSIvPgoKICA8dGV4dCB4PSI2MCIgeT0iMTMyIiBmaWxsPSIjZTJlOGY0IiBmb250LXNpemU9IjE4IiBmb250LXdlaWdodD0iNzAwIj5NZWRpYW48L3RleHQ+CiAgPHRleHQgeD0iNjAiIHk9IjE1MiIgZmlsbD0iIzg2ZWZhYyIgZm9udC1zaXplPSIxNCI+aGlzdG9ncmFtX3F1YW50aWxlIMK3IHVzYWJsZSwgYnV0IGNvYXJzZTwvdGV4dD4KICA8dGV4dCB4PSI2NDAiIHk9IjEzMiIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxOCIgZm9udC13ZWlnaHQ9IjcwMCI+TWVhbjwvdGV4dD4KICA8dGV4dCB4PSI2NDAiIHk9IjE1MiIgZmlsbD0iI2ZjYTVhNSIgZm9udC1zaXplPSIxNCI+c3VtIC8gY291bnQgwrcgZGVzdHJveWVkIGJ5IDAuNSB0byAwLjklIG9mIGJsb2NrczwvdGV4dD4KCiAgPGcgc3Ryb2tlPSIjMTYxZTQ0IiBzdHJva2Utd2lkdGg9IjEiPgogICAgPGxpbmUgeDE9IjYwIiB5MT0iMTk2IiB4Mj0iMTE0MCIgeTI9IjE5NiIvPgogICAgPGxpbmUgeDE9IjYwIiB5MT0iMjQwIiB4Mj0iMTE0MCIgeTI9IjI0MCIvPgogICAgPGxpbmUgeDE9IjYwIiB5MT0iMjg0IiB4Mj0iMTE0MCIgeTI9IjI4NCIvPgogICAgPGxpbmUgeDE9IjYwIiB5MT0iMzI4IiB4Mj0iMTE0MCIgeTI9IjMyOCIvPgogICAgPGxpbmUgeDE9IjYwIiB5MT0iMzcyIiB4Mj0iMTE0MCIgeTI9IjM3MiIvPgogIDwvZz4KCiAgPCEtLSBMRUZUOiBtZWRpYW5zLiB4MD0yMDAsIDAuLjIuNXMgLT4gMzQwcHggKDEzNiBweC9zKSAtLT4KICA8ZyBzdHJva2U9IiMxYzI2NTQiIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8bGluZSB4MT0iMzM2IiB5MT0iMTcwIiB4Mj0iMzM2IiB5Mj0iMzk2Ii8+CiAgICA8bGluZSB4MT0iNDcyIiB5MT0iMTcwIiB4Mj0iNDcyIiB5Mj0iMzk2Ii8+CiAgPC9nPgogIDxnIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiIHRleHQtYW5jaG9yPSJtaWRkbGUiPgogICAgPHRleHQgeD0iMjAwIiB5PSI0MTQiPjA8L3RleHQ+PHRleHQgeD0iMzM2IiB5PSI0MTQiPjEgczwvdGV4dD48dGV4dCB4PSI0NzIiIHk9IjQxNCI+MiBzPC90ZXh0PgogIDwvZz4KICA8dGV4dCB4PSIxOTAiIHk9IjIwMCIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9ImVuZCI+RXJpZ29uPC90ZXh0PgogIDxyZWN0IHg9IjIwMCIgeT0iMTg0IiB3aWR0aD0iMjYzLjYiIGhlaWdodD0iMjAiIHJ4PSIzIiBmaWxsPSIjMjJjNTVlIi8+PHRleHQgeD0iNDcyIiB5PSIyMDAiIGZpbGw9IiM4NmVmYWMiIGZvbnQtc2l6ZT0iMTMiPjEuOTM4IHM8L3RleHQ+CiAgPHRleHQgeD0iMTkwIiB5PSIyNDQiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJlbmQiPkdldGg8L3RleHQ+CiAgPHJlY3QgeD0iMjAwIiB5PSIyMjgiIHdpZHRoPSIyNjMuNyIgaGVpZ2h0PSIyMCIgcng9IjMiIGZpbGw9IiMyMmM1NWUiLz48dGV4dCB4PSI0NzIiIHk9IjI0NCIgZmlsbD0iIzg2ZWZhYyIgZm9udC1zaXplPSIxMyI+MS45MzkgczwvdGV4dD4KICA8dGV4dCB4PSIxOTAiIHk9IjI4OCIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9ImVuZCI+QmVzdTwvdGV4dD4KICA8cmVjdCB4PSIyMDAiIHk9IjI3MiIgd2lkdGg9IjI2NC4yIiBoZWlnaHQ9IjIwIiByeD0iMyIgZmlsbD0iIzIyYzU1ZSIvPjx0ZXh0IHg9IjQ3MyIgeT0iMjg4IiBmaWxsPSIjODZlZmFjIiBmb250LXNpemU9IjEzIj4xLjk0MyBzPC90ZXh0PgogIDx0ZXh0IHg9IjE5MCIgeT0iMzMyIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0iZW5kIj5OZXRoZXJtaW5kPC90ZXh0PgogIDxyZWN0IHg9IjIwMCIgeT0iMzE2IiB3aWR0aD0iMjY0LjIiIGhlaWdodD0iMjAiIHJ4PSIzIiBmaWxsPSIjMjJjNTVlIi8+PHRleHQgeD0iNDczIiB5PSIzMzIiIGZpbGw9IiM4NmVmYWMiIGZvbnQtc2l6ZT0iMTMiPjEuOTQzIHM8L3RleHQ+CiAgPHRleHQgeD0iMTkwIiB5PSIzNzYiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJlbmQiPkV0aHJleDwvdGV4dD4KICA8cmVjdCB4PSIyMDAiIHk9IjM2MCIgd2lkdGg9IjI2NC44IiBoZWlnaHQ9IjIwIiByeD0iMyIgZmlsbD0iIzIyYzU1ZSIvPjx0ZXh0IHg9IjQ3NCIgeT0iMzc2IiBmaWxsPSIjODZlZmFjIiBmb250LXNpemU9IjEzIj4xLjk0NyBzPC90ZXh0PgogIDx0ZXh0IHg9IjIwMCIgeT0iNDQwIiBmaWxsPSIjOGU5YmJkIiBmb250LXNpemU9IjEzIj5hbGwgZml2ZSBpbnNpZGUgdGhlIDEtdG8tMi41IHMgYnVja2V0LCB3aGljaCBob2xkcyA3NSUgb2YgdGhlIGRhdGE8L3RleHQ+CgogIDwhLS0gUklHSFQ6IG1lYW5zLiB4MD03MDAsIDAuLjIwcyAtPiAzODBweCAoMTkgcHgvcykgLS0+CiAgPGcgc3Ryb2tlPSIjMWMyNjU0IiBzdHJva2Utd2lkdGg9IjEiPgogICAgPGxpbmUgeDE9Ijc5NSIgeTE9IjE3MCIgeDI9Ijc5NSIgeTI9IjM5NiIvPgogICAgPGxpbmUgeDE9Ijg5MCIgeTE9IjE3MCIgeDI9Ijg5MCIgeTI9IjM5NiIvPgogICAgPGxpbmUgeDE9Ijk4NSIgeTE9IjE3MCIgeDI9Ijk4NSIgeTI9IjM5NiIvPgogICAgPGxpbmUgeDE9IjEwODAiIHkxPSIxNzAiIHgyPSIxMDgwIiB5Mj0iMzk2Ii8+CiAgPC9nPgogIDxnIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiIHRleHQtYW5jaG9yPSJtaWRkbGUiPgogICAgPHRleHQgeD0iNzAwIiB5PSI0MTQiPjA8L3RleHQ+PHRleHQgeD0iNzk1IiB5PSI0MTQiPjUgczwvdGV4dD48dGV4dCB4PSI4OTAiIHk9IjQxNCI+MTAgczwvdGV4dD48dGV4dCB4PSI5ODUiIHk9IjQxNCI+MTUgczwvdGV4dD48dGV4dCB4PSIxMDgwIiB5PSI0MTQiPjIwIHM8L3RleHQ+CiAgPC9nPgogIDxyZWN0IHg9IjcwMCIgeT0iMTg0IiB3aWR0aD0iMTY3LjIiIGhlaWdodD0iMjAiIHJ4PSIzIiBmaWxsPSIjZjk3MzE2Ii8+PHRleHQgeD0iODc1IiB5PSIyMDAiIGZpbGw9IiNmYjkyM2MiIGZvbnQtc2l6ZT0iMTMiPjguOCBzPC90ZXh0PgogIDxyZWN0IHg9IjcwMCIgeT0iMjI4IiB3aWR0aD0iMzY0LjgiIGhlaWdodD0iMjAiIHJ4PSIzIiBmaWxsPSIjZjk3MzE2Ii8+PHRleHQgeD0iMTA3MiIgeT0iMjQ0IiBmaWxsPSIjZmI5MjNjIiBmb250LXNpemU9IjEzIj4xOS4yIHM8L3RleHQ+CiAgPHJlY3QgeD0iNzAwIiB5PSIyNzIiIHdpZHRoPSIzNDIuMCIgaGVpZ2h0PSIyMCIgcng9IjMiIGZpbGw9IiNmOTczMTYiLz48dGV4dCB4PSIxMDUwIiB5PSIyODgiIGZpbGw9IiNmYjkyM2MiIGZvbnQtc2l6ZT0iMTMiPjE4LjAgczwvdGV4dD4KICA8cmVjdCB4PSI3MDAiIHk9IjMxNiIgd2lkdGg9IjM3Ny40IiBoZWlnaHQ9IjIwIiByeD0iMyIgZmlsbD0iI2Y5NzMxNiIvPjx0ZXh0IHg9IjEwODUiIHk9IjMzMiIgZmlsbD0iI2ZiOTIzYyIgZm9udC1zaXplPSIxMyI+MTkuOSBzPC90ZXh0PgogIDxyZWN0IHg9IjcwMCIgeT0iMzYwIiB3aWR0aD0iMzY0LjgiIGhlaWdodD0iMjAiIHJ4PSIzIiBmaWxsPSIjZjk3MzE2Ii8+PHRleHQgeD0iMTA3MiIgeT0iMzc2IiBmaWxsPSIjZmI5MjNjIiBmb250LXNpemU9IjEzIj4xOS4yIHM8L3RleHQ+CiAgPHRleHQgeD0iNzAwIiB5PSI0NDAiIGZpbGw9IiNmYjkyM2MiIGZvbnQtc2l6ZT0iMTQiIGZvbnQtd2VpZ2h0PSI2MDAiPjExIHMgb2Ygc3ByZWFkIMK3IHJhdGlvcyA0LjV4IHRvIDEwLjJ4PC90ZXh0PgoKICA8dGV4dCB4PSI0OCIgeT0iNDcyIiBmaWxsPSIjZmRlNjhhIiBmb250LXNpemU9IjE1Ij5PbiB0aGUgbWVhbiwgRXJpZ29uIGxvb2tzIHR3aWNlIGFzIGZhc3QgYXMgdGhlIHJlc3QuIFRoYXQgaXMgaG93IG1hbnkgc3RyYWdnbGVycyBpdCBzYXcsIG5vdCBob3cgZmFzdCBpdCBpcy48L3RleHQ+CiAgPHRleHQgeD0iNDgiIHk9IjQ5MiIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMiI+VG9wIGZpbml0ZSBidWNrZXQgaXMgMTAgczsgMC41MSUgdG8gMC44OCUgb2Ygb2JzZXJ2YXRpb25zIGV4Y2VlZCBpdCBhbmQgc3VtL2NvdW50IHdlaWdodHMgdGhlbSBhdCBmdWxsIHZhbHVlLiBUaGUgbWVkaWFucyBzaXQgaW5zaWRlIHRoZSAxLXRvLTIuNSBzIGJ1Y2tldCwgc28gd2UgcXVvdGUgbm8gY3Jvc3MtY2xpZW50IHNwcmVhZCBmcm9tIHRoZW0uIFJldGggZXhjbHVkZWQuPC90ZXh0PgogIDx0ZXh0IHg9IjExNTIiIHk9IjQ5MiIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9ImVuZCI+ZG9jcy5zdGVyZXVtbGFicy5jb208L3RleHQ+Cjwvc3ZnPgo=" width="1200" height="500" class="img_ev3q"></p>
<table><thead><tr><th>Execution client</th><th>Median</th><th>Mean of the same data</th><th>Ratio</th></tr></thead><tbody><tr><td>Erigon</td><td>1.938 s</td><td>8.8 s</td><td>4.5x</td></tr><tr><td>Geth</td><td>1.939 s</td><td>19.2 s</td><td>9.9x</td></tr><tr><td>Besu</td><td>1.943 s</td><td>18.0 s</td><td>9.3x</td></tr><tr><td>Nethermind</td><td>1.943 s</td><td>19.9 s</td><td>10.2x</td></tr><tr><td>Ethrex</td><td>1.947 s</td><td>19.2 s</td><td>9.9x</td></tr></tbody></table>
<p>Between 0.51% and 0.88% of observations exceed the top finite bucket of 10 s. The histogram can only record them as "past 10 s"; <code>sum/count</code> weights them at their true magnitude, and each of them averages many minutes past slot start rather than seconds. That is enough to move the mean by an order of magnitude, and by different amounts per pairing, so a dashboard panel built on <code>sum/count</code> invents a 2.3x spread between execution clients out of nothing but how many stragglers each one saw.</p>
<p>What we will not do is turn the median column into a finding. Three quarters of the data, 74.9 to 75.5%, sits in a single bucket spanning 1 s to 2.5 s: 77.6 to 78.3% of observations fall at or below 2.5 s and only 2.7% below 1 s. So <code>histogram_quantile</code> is interpolating the median across that one bucket and the nine milliseconds separating the five pairings reflects bucket occupancy rather than arrival timing. This series has an arrival control built from Lighthouse, Nimbus and Prysm, whose buckets or gauges can carry it. Grandine's cannot, and saying so is more useful than a fourth data point that would not mean what the first three mean.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-driver-effect-what-replicates-is-a-split-not-an-order">The driver effect: what replicates is a split, not an order<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-grandine#the-driver-effect-what-replicates-is-a-split-not-an-order" class="hash-link" aria-label="Direct link to The driver effect: what replicates is a split, not an order" title="Direct link to The driver effect: what replicates is a split, not an order" translate="no">​</a></h2>
<p><a class="" href="https://docs.stereumlabs.com/blog/where-the-slot-goes-prysm">Part three</a> found that the same execution client, same version, on equally loaded identical machines, runs materially slower under some consensus clients than others, and left the mechanism open. We now have a second window and finer granularity, and the finding needs both a confirmation and a correction.</p>
<p><img decoding="async" loading="lazy" alt="Nethermind&amp;#39;s own payload execution time under six consensus clients across twelve twelve-hour sub-windows: a two-tier split with Grandine, Teku and Lighthouse consistently below Nimbus, Lodestar and Prysm, while the order inside each tier changes repeatedly" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDUyMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNTIwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNDgiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjYiIGZvbnQtd2VpZ2h0PSI3MDAiPldoYXQgcmVwbGljYXRlcyBpcyBhIHNwbGl0LCBub3QgYW4gb3JkZXI8L3RleHQ+CiAgPHRleHQgeD0iNDgiIHk9Ijc2IiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE1Ij5OZXRoZXJtaW5kIDEuMzkuMiB0aW1pbmcgaXRzIG93biBwYXlsb2FkIGV4ZWN1dGlvbiwgYnkgZHJpdmVyIMK3IHR3ZWx2ZSB0d2VsdmUtaG91ciBzdWItd2luZG93cywgMjAyNi0wNy0yNCB0byAwNy0zMDwvdGV4dD4KCiAgPCEtLSB5IGF4aXMgLS0+CiAgPGcgc3Ryb2tlPSIjMWMyNjU0IiBzdHJva2Utd2lkdGg9IjEiPgogICAgPGxpbmUgeDE9IjE4MCIgeTE9IjE0MCIgeDI9IjEwMDAiIHkyPSIxNDAiLz4KICAgIDxsaW5lIHgxPSIxODAiIHkxPSIyNDQiIHgyPSIxMDAwIiB5Mj0iMjQ0Ii8+CiAgICA8bGluZSB4MT0iMTgwIiB5MT0iMzQ4IiB4Mj0iMTAwMCIgeTI9IjM0OCIvPgogIDwvZz4KICA8ZyBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEyIiB0ZXh0LWFuY2hvcj0iZW5kIj4KICAgIDx0ZXh0IHg9IjE3MCIgeT0iMTQ0Ij41MDAgbXM8L3RleHQ+CiAgICA8dGV4dCB4PSIxNzAiIHk9IjI0OCI+MzAwIG1zPC90ZXh0PgogICAgPHRleHQgeD0iMTcwIiB5PSIzNTIiPjEwMCBtczwvdGV4dD4KICA8L2c+CgogIDwhLS0gdGhlIGdhcCBiYW5kOiBiZXR3ZWVuIHRoZSBzbG93ZXN0IGZhc3QtdGllciBkcml2ZXIgYW5kIHRoZSBmYXN0ZXN0IHNsb3ctdGllciBkcml2ZXIgLS0+CiAgPHBvbHlnb24gZmlsbD0iIzUwNDZlNSIgb3BhY2l0eT0iMC4xNyIgcG9pbnRzPSIxODAsMjcwLjQgMjU0LjUsMzA1LjcgMzI5LDI0OC4zIDQwMy41LDI2My4zIDQ3OCwyMDMuMCA1NTIuNSwyODcuOCA2MjcsMjY2LjAgNzAxLjUsMzA2LjkgNzc2LDI3Ny4zIDg1MC41LDI4OC43IDkyNSwyNTYuNiA5OTkuNSwzMTEuNCA5OTkuNSwyNzIuMSA5MjUsMjI4LjggODUwLjUsMjM5LjcgNzc2LDIyOS4yIDcwMS41LDI3My43IDYyNywyMjQuMiA1NTIuNSwyNDUuMSA0NzgsMTk0LjIgNDAzLjUsMjM2LjcgMzI5LDIyNi45IDI1NC41LDI4My41IDE4MCwyNDQuMyIvPgoKICA8IS0tIGZhc3QgdGllciAtLT4KICA8cG9seWxpbmUgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMjJjNTVlIiBzdHJva2Utd2lkdGg9IjIuNSIgcG9pbnRzPSIxODAsMjk4LjIgMjU0LjUsMzI5LjkgMzI5LDI5Ni4yIDQwMy41LDI5MS42IDQ3OCwyNjYuNSA1NTIuNSwzMTAuNiA2MjcsMjg4LjYgNzAxLjUsMzI1LjYgNzc2LDMwOC4yIDg1MC41LDMxMy4zIDkyNSwyOTAuMSA5OTkuNSwzMjcuMyIvPgogIDxwb2x5bGluZSBmaWxsPSJub25lIiBzdHJva2U9IiNmZGU2OGEiIHN0cm9rZS13aWR0aD0iMS44IiBwb2ludHM9IjE4MCwyNzAuNCAyNTQuNSwzMjQuNyAzMjksMjc0LjUgNDAzLjUsMjc0LjkgNDc4LDIxOC45IDU1Mi41LDI5MC4wIDYyNywyNzguNyA3MDEuNSwzMDYuOSA3NzYsMjkwLjkgODUwLjUsMjk3LjYgOTI1LDI2OS43IDk5OS41LDMxOS44Ii8+CiAgPHBvbHlsaW5lIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2ZjYTVhNSIgc3Ryb2tlLXdpZHRoPSIxLjgiIHBvaW50cz0iMTgwLDI3MC43IDI1NC41LDMwNS43IDMyOSwyNDguMyA0MDMuNSwyNjMuMyA0NzgsMjAzLjAgNTUyLjUsMjg3LjggNjI3LDI2Ni4wIDcwMS41LDMxNC41IDc3NiwyNzcuMyA4NTAuNSwyODguNyA5MjUsMjU2LjYgOTk5LjUsMzExLjQiLz4KCiAgPCEtLSBzbG93IHRpZXIgLS0+CiAgPHBvbHlsaW5lIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2M0YjVmZCIgc3Ryb2tlLXdpZHRoPSIxLjgiIHBvaW50cz0iMTgwLDI0NC4zIDI1NC41LDI4My41IDMyOSwyMjYuOSA0MDMuNSwyMzYuNyA0NzgsMTk0LjIgNTUyLjUsMjQ1LjEgNjI3LDIyNC4yIDcwMS41LDI2Ni4zIDc3NiwyMjkuMiA4NTAuNSwyMjQuMiA5MjUsMjI4LjggOTk5LjUsMjcwLjQiLz4KICA8cG9seWxpbmUgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMzhiZGY4IiBzdHJva2Utd2lkdGg9IjEuOCIgcG9pbnRzPSIxODAsMjIxLjkgMjU0LjUsMjgxLjUgMzI5LDIwNi40IDQwMy41LDIxMi4wIDQ3OCwxNzUuMSA1NTIuNSwyMzguMiA2MjcsMjE5LjAgNzAxLjUsMjczLjcgNzc2LDIwOS4zIDg1MC41LDIzOS43IDkyNSwyMDIuNSA5OTkuNSwyNjkuOCIvPgogIDxwb2x5bGluZSBmaWxsPSJub25lIiBzdHJva2U9IiNmOTczMTYiIHN0cm9rZS13aWR0aD0iMi41IiBwb2ludHM9IjE4MCwyMTUuNyAyNTQuNSwyNjcuOSAzMjksMjA0LjIgNDAzLjUsMjA4LjggNDc4LDE2Mi4yIDU1Mi41LDIzMi44IDYyNywyMTMuNiA3MDEuNSwyNzIuMSA3NzYsMjEzLjUgODUwLjUsMjM3LjcgOTI1LDE5NC44IDk5OS41LDI3Mi4xIi8+CgogIDx0ZXh0IHg9IjEwMTAiIHk9IjIwMCIgZmlsbD0iI2Y5NzMxNiIgZm9udC1zaXplPSIxMyIgZm9udC13ZWlnaHQ9IjYwMCI+UHJ5c208L3RleHQ+CiAgPHRleHQgeD0iMTAxMCIgeT0iMjE4IiBmaWxsPSIjMzhiZGY4IiBmb250LXNpemU9IjEzIj5Mb2Rlc3RhcjwvdGV4dD4KICA8dGV4dCB4PSIxMDEwIiB5PSIyMzYiIGZpbGw9IiNjNGI1ZmQiIGZvbnQtc2l6ZT0iMTMiPk5pbWJ1czwvdGV4dD4KICA8dGV4dCB4PSIxMDEwIiB5PSIyNzIiIGZpbGw9IiNmY2E1YTUiIGZvbnQtc2l6ZT0iMTMiPkxpZ2h0aG91c2U8L3RleHQ+CiAgPHRleHQgeD0iMTAxMCIgeT0iMjkwIiBmaWxsPSIjZmRlNjhhIiBmb250LXNpemU9IjEzIj5UZWt1PC90ZXh0PgogIDx0ZXh0IHg9IjEwMTAiIHk9IjMwOCIgZmlsbD0iIzIyYzU1ZSIgZm9udC1zaXplPSIxMyIgZm9udC13ZWlnaHQ9IjYwMCI+R3JhbmRpbmU8L3RleHQ+CgogIDx0ZXh0IHg9IjEwMTAiIHk9IjI1MiIgZmlsbD0iIzhiOGZmNSIgZm9udC1zaXplPSIxMiIgZm9udC13ZWlnaHQ9IjYwMCI+dGhlIGdhcDwvdGV4dD4KCiAgPGcgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMSIgdGV4dC1hbmNob3I9Im1pZGRsZSI+CiAgICA8dGV4dCB4PSIxODAiIHk9IjM3MiI+MDctMjQ8L3RleHQ+PHRleHQgeD0iNDc4IiB5PSIzNzIiPjA3LTI2PC90ZXh0Pjx0ZXh0IHg9Ijc3NiIgeT0iMzcyIj4wNy0yODwvdGV4dD48dGV4dCB4PSI5OTkuNSIgeT0iMzcyIj4wNy0zMDwvdGV4dD4KICA8L2c+CgogIDx0ZXh0IHg9IjQ4IiB5PSI0MTAiIGZpbGw9IiNmZGU2OGEiIGZvbnQtc2l6ZT0iMTUiPlRoZSBzaGFkZWQgZ2FwIG5ldmVyIGNsb3Nlcy4gSW4gYWxsIHR3ZWx2ZSBzdWItd2luZG93cyB0aGUgc2xvd2VzdCBvZiBHcmFuZGluZSwgVGVrdSBhbmQgTGlnaHRob3VzZSBzdGF5cyBiZWxvdyB0aGUgZmFzdGVzdCBvZiBOaW1idXMsIExvZGVzdGFyIGFuZCBQcnlzbS48L3RleHQ+CiAgPHRleHQgeD0iNDgiIHk9IjQzNCIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxNCI+R3JhbmRpbmUgaXMgZmFzdGVzdCBpbiBhbGwgdHdlbHZlLiBCdXQgaW5zaWRlIGVhY2ggdGllciB0aGUgb3JkZXIgZmxpcHM6IFRla3UgYWdhaW5zdCBMaWdodGhvdXNlIGluIDIgb2YgMTIsIExvZGVzdGFyIGFnYWluc3QgUHJ5c20gaW4gMiBvZiAxMi48L3RleHQ+CiAgPHRleHQgeD0iNDgiIHk9IjQ1OCIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxNCI+U28gcGFydCB0aHJlZSdzIHNpeC13YXkgb3JkZXJpbmcgd2FzIGFuIGFydGlmYWN0IG9mIHRocmVlLWRheSBhZ2dyZWdhdGlvbi4gQSB0d28tdGllciBzcGxpdCBpcyB3aGF0IHRoZSBkYXRhIGNhcnJpZXMuPC90ZXh0PgogIDx0ZXh0IHg9IjQ4IiB5PSI0OTIiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiPm5ldGhlcm1pbmRfbmV3X3BheWxvYWRfZXhlY3V0aW9uX3RpbWUsIGVjX3ZlcnNpb24gMS4zOS4yLCBhdmdfb3Zlcl90aW1lWzEyaF0uIEFsbCBzaXggaG9zdHMgYXJlIGlkZW50aWNhbCAxMi1jb3JlIGJhcmUgbWV0YWwgaW4gb25lIHJhY2ssIGVxdWFsbHkgbG9hZGVkLjwvdGV4dD4KICA8dGV4dCB4PSIxMTUyIiB5PSI0OTIiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiIHRleHQtYW5jaG9yPSJlbmQiPmRvY3Muc3RlcmV1bWxhYnMuY29tPC90ZXh0Pgo8L3N2Zz4K" width="1200" height="520" class="img_ev3q"></p>
<table><thead><tr><th>Driven by</th><th>2026-07-24 to 07-27</th><th>2026-07-27 to 07-30</th></tr></thead><tbody><tr><td>Grandine</td><td>195 ms</td><td>175 ms</td></tr><tr><td>Teku</td><td>239 ms</td><td>204 ms</td></tr><tr><td>Lighthouse</td><td>263 ms</td><td>219 ms</td></tr><tr><td>Nimbus</td><td>311 ms</td><td>307 ms</td></tr><tr><td>Lodestar</td><td>341 ms</td><td>316 ms</td></tr><tr><td>Prysm</td><td>355 ms</td><td>319 ms</td></tr></tbody></table>
<p>Confirmed: there are two tiers, and the gap between them holds. Split those twelve-hour sub-windows across both three-day windows and the boundary holds in <strong>12 of 12</strong>: the slowest of Grandine, Teku and Lighthouse is below the fastest of Nimbus, Lodestar and Prysm every single time. Grandine is the fastest driver in all twelve.</p>
<p>Corrected: the six-way ordering in the table above is an artifact of aggregating three days. Teku and Lighthouse trade places in 2 of the 12 sub-windows, and so do Lodestar and Prysm, because inside each tier the clients sit within a few percent of each other. Part three read an ordering; what the data supports is a split, and we would have overstated it without checking the sub-windows. The magnitudes also fell unevenly between the two windows, by 1.3% for Nimbus and 16.5% for Lighthouse, so the earlier reading that "every value came down 10 to 20%" was too tidy as well. Whatever moved them all downward was not a change in what we ask of the fleet: the mirrored validator-client load it serves was unchanged across both windows.</p>
<p>Three limits on the split itself, because a tier boundary is the kind of finding that is easy to draw around whatever the data happened to do. We defined the boundary after seeing these twelve windows, so "holds in 12 of 12" is a description of the data it was drawn on and not an out-of-sample test. It is also resolution-dependent: at six-hour granularity the two tiers overlap in 2 of 24 sub-windows, once by 2 ms and once by 36 ms. And each driver here is one consensus client on one execution-client host, so a driver effect and a host effect cannot be separated at a 62 ms tier gap, which is why part three's host-equivalence checks matter and why we still call the mechanism open.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="and-the-two-execution-clients-disagree-about-the-drivers">And the two execution clients disagree about the drivers<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-grandine#and-the-two-execution-clients-disagree-about-the-drivers" class="hash-link" aria-label="Direct link to And the two execution clients disagree about the drivers" title="Direct link to And the two execution clients disagree about the drivers" translate="no">​</a></h2>
<p>Erigon publishes its own slot timeline, <code>block_consumer_delay</code>, with the moment it had the block body, execution start and execution end. Same version everywhere, same window:</p>
<p><img decoding="async" loading="lazy" alt="Nethermind and Erigon each ranking the six consensus clients that drive them, with lines crossing: Grandine is Nethermind&amp;#39;s fastest driver and Erigon&amp;#39;s fourth, while Lodestar and Nimbus sit fifth and fourth for Nethermind and tie at the top for Erigon" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDU0MCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNTQwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTIiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjciIGZvbnQtd2VpZ2h0PSI3MDAiPlRoZSBkcml2ZXIgb3JkZXIgaXMgbm90IGEgcHJvcGVydHkgb2YgdGhlIGRyaXZlcjwvdGV4dD4KICA8dGV4dCB4PSI0OCIgeT0iODIiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTYiPnR3byBleGVjdXRpb24gY2xpZW50cywgZWFjaCB0aW1pbmcgaXRzZWxmLCByYW5raW5nIHRoZSBzYW1lIHNpeCBjb25zZW5zdXMgY2xpZW50cyB0aGF0IGRyaXZlIHRoZW08L3RleHQ+CgogIDx0ZXh0IHg9IjM4MCIgeT0iMTMwIiBmaWxsPSIjZTJlOGY0IiBmb250LXNpemU9IjE3IiBmb250LXdlaWdodD0iNzAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5OZXRoZXJtaW5kIDEuMzkuMjwvdGV4dD4KICA8dGV4dCB4PSIzODAiIHk9IjE1MCIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9Im1pZGRsZSI+aXRzIG93biBwYXlsb2FkIGV4ZWN1dGlvbiB0aW1lPC90ZXh0PgogIDx0ZXh0IHg9IjgyMCIgeT0iMTMwIiBmaWxsPSIjZTJlOGY0IiBmb250LXNpemU9IjE3IiBmb250LXdlaWdodD0iNzAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5Fcmlnb24gdjMuNS4yPC90ZXh0PgogIDx0ZXh0IHg9IjgyMCIgeT0iMTUwIiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5pdHMgb3duIGV4ZWN1dGlvbiBzcGFuPC90ZXh0PgoKICA8ZyBzdHJva2U9IiMxNjFlNDQiIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8bGluZSB4MT0iMzMwIiB5MT0iMTgwIiB4Mj0iODcwIiB5Mj0iMTgwIi8+CiAgICA8bGluZSB4MT0iMzMwIiB5MT0iMjI4IiB4Mj0iODcwIiB5Mj0iMjI4Ii8+CiAgICA8bGluZSB4MT0iMzMwIiB5MT0iMjc2IiB4Mj0iODcwIiB5Mj0iMjc2Ii8+CiAgICA8bGluZSB4MT0iMzMwIiB5MT0iMzI0IiB4Mj0iODcwIiB5Mj0iMzI0Ii8+CiAgICA8bGluZSB4MT0iMzMwIiB5MT0iMzcyIiB4Mj0iODcwIiB5Mj0iMzcyIi8+CiAgICA8bGluZSB4MT0iMzMwIiB5MT0iNDIwIiB4Mj0iODcwIiB5Mj0iNDIwIi8+CiAgPC9nPgogIDxnIGZpbGw9IiM1NDYwN2QiIGZvbnQtc2l6ZT0iMTIiIHRleHQtYW5jaG9yPSJlbmQiPgogICAgPHRleHQgeD0iMzE4IiB5PSIxODQiPmZhc3Rlc3Q8L3RleHQ+CiAgICA8dGV4dCB4PSIzMTgiIHk9IjQyNCI+c2xvd2VzdDwvdGV4dD4KICA8L2c+CgogIDwhLS0gR3JhbmRpbmU6IE4gcmFuazEgLT4gRSByYW5rNCAtLT4KICA8cG9seWxpbmUgcG9pbnRzPSIzODAsMTgwIDgyMCwzMjQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzIyYzU1ZSIgc3Ryb2tlLXdpZHRoPSIzLjUiLz4KICA8Y2lyY2xlIGN4PSIzODAiIGN5PSIxODAiIHI9IjYiIGZpbGw9IiMyMmM1NWUiLz48Y2lyY2xlIGN4PSI4MjAiIGN5PSIzMjQiIHI9IjYiIGZpbGw9IiMyMmM1NWUiLz4KICA8dGV4dCB4PSIzNzAiIHk9IjE3MiIgZmlsbD0iIzg2ZWZhYyIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9ImVuZCI+R3JhbmRpbmUgMTc1IG1zPC90ZXh0PgogIDx0ZXh0IHg9IjgzMiIgeT0iMzI5IiBmaWxsPSIjODZlZmFjIiBmb250LXNpemU9IjEzIj5HcmFuZGluZSAwLjU4MiBzPC90ZXh0PgoKICA8IS0tIFRla3U6IE4gcmFuazIgLT4gRSByYW5rNSAtLT4KICA8cG9seWxpbmUgcG9pbnRzPSIzODAsMjI4IDgyMCwzNzIiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2ZkZTY4YSIgc3Ryb2tlLXdpZHRoPSIyLjUiIHN0cm9rZS1kYXNoYXJyYXk9IjYgNCIvPgogIDxjaXJjbGUgY3g9IjM4MCIgY3k9IjIyOCIgcj0iNSIgZmlsbD0iI2ZkZTY4YSIvPjxjaXJjbGUgY3g9IjgyMCIgY3k9IjM3MiIgcj0iNSIgZmlsbD0iI2ZkZTY4YSIvPgogIDx0ZXh0IHg9IjM3MCIgeT0iMjIyIiBmaWxsPSIjZmRlNjhhIiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0iZW5kIj5UZWt1IDIwNCBtczwvdGV4dD4KICA8dGV4dCB4PSI4MzIiIHk9IjM3NyIgZmlsbD0iI2ZkZTY4YSIgZm9udC1zaXplPSIxMyI+VGVrdSAwLjY5OSBzPC90ZXh0PgoKICA8IS0tIExpZ2h0aG91c2U6IE4gcmFuazMgLT4gRSByYW5rNiAoc2xvd2VzdCkgLS0+CiAgPHBvbHlsaW5lIHBvaW50cz0iMzgwLDI3NiA4MjAsNDIwIiBmaWxsPSJub25lIiBzdHJva2U9IiNmY2E1YTUiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtZGFzaGFycmF5PSI2IDQiLz4KICA8Y2lyY2xlIGN4PSIzODAiIGN5PSIyNzYiIHI9IjUiIGZpbGw9IiNmY2E1YTUiLz48Y2lyY2xlIGN4PSI4MjAiIGN5PSI0MjAiIHI9IjUiIGZpbGw9IiNmY2E1YTUiLz4KICA8dGV4dCB4PSIzNzAiIHk9IjI3MCIgZmlsbD0iI2ZjYTVhNSIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9ImVuZCI+TGlnaHRob3VzZSAyMTkgbXM8L3RleHQ+CiAgPHRleHQgeD0iODMyIiB5PSI0MjUiIGZpbGw9IiNmY2E1YTUiIGZvbnQtc2l6ZT0iMTMiPkxpZ2h0aG91c2UgMC43NjcgczwvdGV4dD4KCiAgPCEtLSBOaW1idXM6IE4gcmFuazQgLT4gRSByYW5rMiAtLT4KICA8cG9seWxpbmUgcG9pbnRzPSIzODAsMzI0IDgyMCwyMjgiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2M0YjVmZCIgc3Ryb2tlLXdpZHRoPSIyLjUiIHN0cm9rZS1kYXNoYXJyYXk9IjYgNCIvPgogIDxjaXJjbGUgY3g9IjM4MCIgY3k9IjMyNCIgcj0iNSIgZmlsbD0iI2M0YjVmZCIvPjxjaXJjbGUgY3g9IjgyMCIgY3k9IjIyOCIgcj0iNSIgZmlsbD0iI2M0YjVmZCIvPgogIDx0ZXh0IHg9IjM3MCIgeT0iMzQwIiBmaWxsPSIjYzRiNWZkIiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0iZW5kIj5OaW1idXMgMzA3IG1zPC90ZXh0PgogIDx0ZXh0IHg9IjgzMiIgeT0iMjIyIiBmaWxsPSIjYzRiNWZkIiBmb250LXNpemU9IjEzIj5OaW1idXMgMC41MjUgczwvdGV4dD4KCiAgPCEtLSBMb2Rlc3RhcjogTiByYW5rNSAtPiBFIHJhbmsxIC0tPgogIDxwb2x5bGluZSBwb2ludHM9IjM4MCwzNzIgODIwLDE4MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMzhiZGY4IiBzdHJva2Utd2lkdGg9IjIuNSIgc3Ryb2tlLWRhc2hhcnJheT0iNiA0Ii8+CiAgPGNpcmNsZSBjeD0iMzgwIiBjeT0iMzcyIiByPSI1IiBmaWxsPSIjMzhiZGY4Ii8+PGNpcmNsZSBjeD0iODIwIiBjeT0iMTgwIiByPSI1IiBmaWxsPSIjMzhiZGY4Ii8+CiAgPHRleHQgeD0iMzcwIiB5PSIzODgiIGZpbGw9IiMzOGJkZjgiIGZvbnQtc2l6ZT0iMTMiIHRleHQtYW5jaG9yPSJlbmQiPkxvZGVzdGFyIDMxNiBtczwvdGV4dD4KICA8dGV4dCB4PSI4MzIiIHk9IjE3NCIgZmlsbD0iIzM4YmRmOCIgZm9udC1zaXplPSIxMyI+TG9kZXN0YXIgMC41MTggczwvdGV4dD4KCiAgPCEtLSBQcnlzbTogTiByYW5rNiAtPiBFIHJhbmszIC0tPgogIDxwb2x5bGluZSBwb2ludHM9IjM4MCw0MjAgODIwLDI3NiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZjk3MzE2IiBzdHJva2Utd2lkdGg9IjMuNSIvPgogIDxjaXJjbGUgY3g9IjM4MCIgY3k9IjQyMCIgcj0iNiIgZmlsbD0iI2Y5NzMxNiIvPjxjaXJjbGUgY3g9IjgyMCIgY3k9IjI3NiIgcj0iNiIgZmlsbD0iI2Y5NzMxNiIvPgogIDx0ZXh0IHg9IjM3MCIgeT0iNDM2IiBmaWxsPSIjZmI5MjNjIiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0iZW5kIj5QcnlzbSAzMTkgbXM8L3RleHQ+CiAgPHRleHQgeD0iODMyIiB5PSIyODEiIGZpbGw9IiNmYjkyM2MiIGZvbnQtc2l6ZT0iMTMiPlByeXNtIDAuNTYwIHM8L3RleHQ+CgogIDx0ZXh0IHg9IjQ4IiB5PSI0NzgiIGZpbGw9IiNmZGU2OGEiIGZvbnQtc2l6ZT0iMTUiPk5ldGhlcm1pbmQncyBmYXN0ZXN0IGRyaXZlciBpcyBHcmFuZGluZSBhbmQgaXRzIHNsb3dlc3QgaXMgUHJ5c20uIEZvciBFcmlnb24sIEdyYW5kaW5lIGlzIGZvdXJ0aCBhbmQgTGlnaHRob3VzZSBzbG93ZXN0LCB3aXRoIExvZGVzdGFyIGFuZCBOaW1idXMgdGllZCBhdCB0aGUgdG9wLjwvdGV4dD4KICA8dGV4dCB4PSI0OCIgeT0iNTAwIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE0Ij5SYW5rIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHR3bzogLTAuNjAgb24gdGhlIGV4ZWN1dGlvbiBzcGFuLCAtMC4xNCBvbiBhYnNvbHV0ZSBjb21wbGV0aW9uIHRpbWUuIE5vIGNvbnNpc3RlbnQgcmVsYXRpb25zaGlwLCBpbiBlaXRoZXIgZGlyZWN0aW9uLjwvdGV4dD4KICA8dGV4dCB4PSI0OCIgeT0iNTIyIiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEyIj5Fcmlnb24ncyBzcGFuIGlzIHRoZSBkaWZmZXJlbmNlIG9mIHR3byBjbGllbnQtcmVwb3J0ZWQgbWVkaWFucyBhbmQgYXBwcm94aW1hdGVzIHRoZSB0eXBpY2FsIGV4ZWN1dGlvbiB3aW5kb3c7IExvZGVzdGFyIGxlYWRzIE5pbWJ1cyBieSA2IG1zIGFuZCB0aGV5IHN3YXAgYnkgZGF5LCBzbyByZWFkIHRoZSBjcm9zc2luZywgbm90IHRoZSByYW5rLiBMaWdodGhvdXNlIHJlY29uc3RydWN0ZWQgZnJvbSB0aGUgdHdvIGRheXMgdGhhdCByZXBvcnRlZC4gUmV0aCBleGNsdWRlZC48L3RleHQ+CiAgPHRleHQgeD0iMTE1MiIgeT0iNTIyIiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEyIiB0ZXh0LWFuY2hvcj0iZW5kIj5kb2NzLnN0ZXJldW1sYWJzLmNvbTwvdGV4dD4KPC9zdmc+Cg==" width="1200" height="540" class="img_ev3q"></p>
<table><thead><tr><th>Driven by</th><th>Body available</th><th>Execution starts</th><th>Execution ends</th><th>Span</th></tr></thead><tbody><tr><td>Lodestar</td><td>2.004 s</td><td>2.565 s</td><td>3.084 s</td><td><strong>0.518 s</strong></td></tr><tr><td>Nimbus</td><td>1.829 s</td><td>2.473 s</td><td>2.997 s</td><td>0.525 s</td></tr><tr><td>Prysm</td><td>1.671 s</td><td>2.171 s</td><td>2.731 s</td><td>0.560 s</td></tr><tr><td>Grandine</td><td>1.736 s</td><td>2.176 s</td><td>2.758 s</td><td>0.582 s</td></tr><tr><td>Teku</td><td>1.702 s</td><td>2.349 s</td><td>3.048 s</td><td>0.699 s</td></tr><tr><td>Lighthouse</td><td>1.871 s</td><td>2.606 s</td><td>3.373 s</td><td><strong>0.767 s</strong></td></tr></tbody></table>
<p>Nethermind's fastest driver is Grandine and its slowest is Prysm. For Erigon the slowest is Lighthouse, and the fastest is Lodestar by 6 ms over Nimbus, which is thin enough that the top of this column is a tie rather than a winner: split it by day and Lodestar leads by 23 ms, then the two land within 0.3 ms, then Nimbus leads by 3.5 ms. What survives is the crossing itself. Grandine, first for Nethermind in every one of twelve sub-windows, sits fourth of six here on every one of the three days. Lodestar and Nimbus, fifth and fourth for Nethermind, occupy the top two places here on all three.</p>
<p>How strongly the two disagree depends on which reading of Erigon's timeline you take, and we checked two: on the execution span the rank correlation with Nethermind's order is -0.60, and on absolute execution-end time it is -0.14. Neither is significant at six drivers, and the range between them is the point. There is no consistent relationship, in either direction, between how a driver treats Nethermind and how it treats Erigon.</p>
<p>So part three's open question closes in the only direction the data supports. The driver matters, and it is not a property of the driver: it is specific to the pair. There is no gentle consensus client and no demanding one.</p>
<p>Two limits on this table. The Lighthouse row is reconstructed from the two days of the three that reported, because a single scrape returning no value propagates through <code>avg_over_time</code> and voids the whole window; on both reporting days it was the slowest of the six. And the span column subtracts two separately computed medians, which approximates the typical execution window rather than being the median of a duration. The three fastest spans sit within 42 ms of each other, so what we read from this table is that the two orderings cross, not the position of any single driver in it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-to-measure-on-your-own-grandine-nodes">What to measure on your own Grandine nodes<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-grandine#what-to-measure-on-your-own-grandine-nodes" class="hash-link" aria-label="Direct link to What to measure on your own Grandine nodes" title="Direct link to What to measure on your own Grandine nodes" translate="no">​</a></h2>
<ul>
<li class=""><strong>Inventory before you conclude.</strong> <code>count by (__name__) ({__name__=~".+_bucket", job="grandine"})</code> returns 70 histograms; drop the <code>_bucket</code> filter and you get all 330 metric names it publishes. The keyword searches that sent us wrong returned 0, 2 and 11. If you have ever concluded that a client does not expose something, that is the query to rerun.</li>
<li class=""><strong>Both engine calls are there:</strong> <code>ETH1_API_REQUEST_TIMES{method="engine_newPayloadV4"}</code> and <code>{method="engine_forkchoiceUpdatedV3"}</code>. Watch the second one too; on one execution client it is the larger cost.</li>
<li class=""><strong>Do not chart <code>sum/count</code> on either default-bucket histogram.</strong> On the arrival metric that reads ten times the median. Use <code>histogram_quantile</code>, and know that with 75% of the data in the single 1-to-2.5 s bucket the interpolated quantile is coarse.</li>
<li class=""><strong>Neither histogram can answer the deadline question.</strong> No bucket boundary sits near 4 s. For a share-of-late-blocks figure you need a histogram bucketed with the deadline in mind, which on our fleet means Nimbus or Prysm.</li>
<li class=""><strong>Do not carry a client comparison across pairings.</strong> The driver changes an execution client's measured speed by a wide margin, in tiers that hold and an order that does not, and differently for different execution clients.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="coming-next-in-the-series">Coming next in the series<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-grandine#coming-next-in-the-series" class="hash-link" aria-label="Direct link to Coming next in the series" title="Direct link to Coming next in the series" translate="no">​</a></h2>
<p>Teku and Lodestar remain, and both already appear as drivers above: Teku sits in the fast tier for Nethermind and is second-slowest for Erigon, Lodestar the reverse. Then the finale, where all six clients and all of their instruments go side by side, with an honest list of the claims from earlier editions that did not survive being measured a second way. This edition contributes two entries to that list, both ours: the reading of part three that the driver effect was an ordering, and the premise this post was drafted with.</p>
<p>The pattern in all four editions is that a client comparison is only as good as the instrument you read it through, and that the instrument is easy to misread in ways that look like client differences: a mean poisoned by stragglers, a quantile interpolated across an over-full bucket, an ordering that only exists at one aggregation level, a capability hidden behind a name. Catching those is what StereumLabs AI does on our fleet, on <a class="" href="https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack">the measurement stack we described here</a>, and this edition is a fair sample of how often it catches us. If you run Ethereum infrastructure and want this lens on your own nodes, reach us at <a href="https://stereumlabs.com/" target="_blank" rel="noopener noreferrer" class="">stereumlabs.com</a> or <a href="mailto:contact@stereumlabs.com" target="_blank" rel="noopener noreferrer" class="">contact@stereumlabs.com</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="methodology">Methodology<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-grandine#methodology" class="hash-link" aria-label="Direct link to Methodology" title="Direct link to Methodology" translate="no">​</a></h2>
<p>Numbers come from Grandine's and the execution clients' own metrics on our NDC2 deployment (Vienna), queried on the <code>Prometheus-cold</code> datasource (uid <code>aez9ck4wz05q8e</code>), with the fleet labels documented in <a class="" href="https://docs.stereumlabs.com/docs/dashboards/build-your-own">build your own dashboards</a>. The window is 2026-07-27T00:00:00Z to 2026-07-30T00:00:00Z, with <code>increase(...[3d])</code> and <code>avg_over_time(...[3d])</code> evaluated at the closing anchor so figures are stable and reproducible rather than drifting with query time. No execution-client version changed inside it and Grandine held 2.0.5 throughout.</p>
<ul>
<li class=""><strong>How the instrumentation was established.</strong> <code>count(count by (__name__) ({__name__=~".+_bucket", job="grandine", deployment="NDC2"}))</code> returns 70; the same query without the <code>_bucket</code> filter returns 330 distinct metric names. Run per job across the six consensus clients, evaluated at the window's closing anchor rather than at query time, it gives 158 histograms for Lodestar, 143 for Lighthouse, 70 for Grandine, 65 for Prysm, 25 for Nimbus and 6 for Teku, and 1,160 / 778 / 330 / 591 / 535 / 411 total metric names respectively, which is the basis for saying Grandine is neither the sparse nor the rich end. These counts drift by a few series with query time, which is why we pin them to the anchor like every other figure here. Counts are of metric families exposed on this deployment and include non-timing histograms, so they are a rough measure of surface area rather than of timing coverage. The engine timing is <code>ETH1_API_REQUEST_TIMES</code> (<code>_bucket</code>, <code>_count</code>, <code>_sum</code>), seconds, with a <code>method</code> label taking <code>engine_newPayloadV4</code>, <code>engine_forkchoiceUpdatedV3</code>, <code>engine_getPayloadV5</code>, <code>engine_getBlobsV2</code> and <code>engine_exchangeCapabilities</code>, six series per method, one per pairing. Finite bucket edges for both this and the arrival histogram are 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5 and 10 s. The three name searches that missed it are reproduced in the table above; none of them can match a name that is all-caps and carries its subject in a label.</li>
<li class=""><strong>Engine-call figures.</strong> Means are <code>increase(_sum[3d]) / increase(_count[3d])</code> per <code>ec_client</code>, which is exact. The <code>newPayload</code> 90th percentiles are <code>histogram_quantile</code> over windowed buckets and are interpolated inside the 0.25-to-1 s bucket for Geth, Nethermind and Besu, so treat them as approximate; Erigon's falls in the 1-to-2.5 s bucket. We do not quote quantiles for <code>forkchoiceUpdated</code>, whose 4-to-7 ms values sit below the second bucket edge. Call counts are 21,883 (Ethrex), 22,198 (Nethermind), 22,534 (Geth), 22,933 (Besu) and 23,981 (Erigon) against 21,600 slots carrying 21,521 blocks, so slightly more than one call per block.</li>
<li class=""><strong>The four-instrument Besu comparison</strong> uses <code>execution_layer_request_times{method="forkchoice_updated"}</code> on Lighthouse v8.2.1, <code>engine_api_request_duration_seconds{request="forkchoiceUpdated"}</code> on Nimbus v26.7.0, <code>forkchoice_updated_v1_latency_milliseconds</code> on Prysm v7.1.7 and <code>ETH1_API_REQUEST_TIMES{method="engine_forkchoiceUpdatedV3"}</code> on Grandine 2.0.5, all as windowed means over this edition's window rather than part three's, so all four rows cover the same three days.</li>
<li class=""><strong>The arrival histogram.</strong> Medians are <code>histogram_quantile(0.5, ...)</code>; means are <code>increase(_sum[3d]) / increase(_count[3d])</code>. Share at or below the 10 s bucket: 99.124% Nethermind, 99.139% Geth, 99.156% Ethrex, 99.240% Besu, 99.486% Erigon. Share at or below 2.5 s: 77.58% Ethrex, 77.88% Besu, 77.96% Nethermind, 78.23% Geth, 78.29% Erigon, which is why the interpolated median is coarse and why we do not read a cross-client spread from it. Counts are 21,596 to 21,717 per pairing.</li>
<li class=""><strong>The driver comparison</strong> uses <code>avg_over_time(nethermind_new_payload_execution_time[3d])</code> for <code>ec_version="1.39.2"</code> grouped by <code>cc_client</code>, the execution client's own timer with no consensus client in the measurement. Sub-window stability is the same query at <code>[12h]</code> on a 12-hour step across both three-day windows, twelve points per driver. The tier boundary, defined as the maximum of Grandine, Teku and Lighthouse against the minimum of Nimbus, Lodestar and Prysm, holds in all twelve, and at six-hour granularity in 22 of 24. The boundary was chosen after inspecting these windows, so that is a description of this data rather than an out-of-sample test. Within-tier order changes in 2 of 12 sub-windows for Teku against Lighthouse and 2 of 12 for Lodestar against Prysm. Window-to-window change per driver is Nimbus -1.3%, Lodestar -7.4%, Grandine -9.9%, Prysm -10.1%, Teku -14.8%, Lighthouse -16.5%.</li>
<li class=""><strong>Erigon's timeline</strong> is <code>block_consumer_delay</code> for <code>ec_version="v3.5.2"</code>, a summary with client-computed quantiles; we take <code>avg_over_time</code> of the <code>quantile="0.5"</code> series for <code>type="body_download"</code>, <code>"pre_execution"</code> and <code>"post_execution"</code>, which is the average over the window of Erigon's own reported median rather than a median over the window. The Lighthouse pairing has one scrape with no value inside the window, which voids a three-day <code>avg_over_time</code>, so its row is the mean of the two daily values that did report, 1.835 and 1.907 s for body, 2.589 and 2.623 s for execution start, 3.377 and 3.368 s for execution end. Per-day spans for the other five are Lodestar 0.508/0.516/0.531, Nimbus 0.531/0.516/0.528, Prysm 0.565/0.556/0.559, Grandine 0.593/0.569/0.582 and Teku 0.699/0.688/0.709 s. Spearman rank correlation against Nethermind's driver order is -0.60 using the span and -0.14 using absolute execution-end time; with six drivers neither is significant, and we report the range rather than a single figure. We have not verified from Erigon's source what each <code>type</code> boundary corresponds to internally, so this table is a relative comparison across drivers on one metric rather than an absolute decomposition.</li>
<li class=""><strong><code>MUTATOR_BLOCK_PROCESSING_TIMES</code></strong>, Grandine's per-slot block-processing timer, gives Geth 229, Besu 248, Erigon 254, Ethrex 332 and Nethermind 333 ms over the window. That ordering differs from the <code>newPayload</code> ordering on the same client, and because we cannot say from the metric alone which phases it spans, we report its existence and this disagreement as a caution rather than building a finding on it.</li>
<li class=""><strong>Sync was verified from logs, not metrics.</strong> At both ends of the window each execution client's container log showed it at the chain tip, block 25,620,466 on 2026-07-27 and 25,641,987 on 2026-07-30, via Geth's <code>Chain head was updated</code>, Besu's block-add lines, Erigon's <code>head updated</code>, Nethermind's <code>Received ForkChoice</code> and Ethrex's <code>Prewarm pass for block</code>. Reth is excluded: no <code>Canonical chain committed</code> line appears in its log across the window, Prysm's <code>new_payload_valid_node_count</code> for the Reth pairing increases at zero per hour against about 300 for the other five, and Grandine issued 86,350 <code>newPayload</code> calls to it against about 22,000 for each of the others. On identical 12-core hosts; consensus and validator processes run on separate machines. Our fleet runs no live validators; it receives mirrored validator-client traffic, and that mirroring was unchanged across both windows, so it is not a candidate explanation for the between-window shift.</li>
</ul>]]></content:encoded>
            <category>client comparison</category>
            <category>validator duties</category>
            <category>observability</category>
            <category>engine API</category>
            <category>Grandine</category>
            <category>Prysm</category>
            <category>Geth</category>
            <category>Nethermind</category>
            <category>Besu</category>
            <category>Erigon</category>
            <category>Ethrex</category>
            <category>StereumLabs AI</category>
        </item>
        <item>
            <title><![CDATA[Where the slot goes: Prysm, and what survives three instruments]]></title>
            <link>https://docs.stereumlabs.com/blog/where-the-slot-goes-prysm</link>
            <guid>https://docs.stereumlabs.com/blog/where-the-slot-goes-prysm</guid>
            <pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Three consensus clients time the same engine calls on our fleet. Only the extremes and Besu's 200 ms forkchoiceUpdated survive all three instruments.]]></description>
            <content:encoded><![CDATA[<p>The first two editions of this series each had one instrument. <a class="" href="https://docs.stereumlabs.com/blog/where-the-slot-goes-lighthouse">Under Lighthouse</a> we used its block-delay gauges and found the execution client moved the would-fail-attestation rate up to 3.7x. <a class="" href="https://docs.stereumlabs.com/blog/where-the-slot-goes-nimbus">Under Nimbus</a> we used its arrival histogram and found it could not separate execution clients at all. Prysm gives us fine-grained histograms of both engine calls, one entry per slot, which is what we came for. It also gave us something we did not plan on: enough overlap with the other two clients to put the same question to three independent instruments on three separate pairings, in the same three days, on identical execution-client versions.</p>
<p>That triangulation is the finding, and it changes how we read our own earlier editions. Two results survive all three instruments: Ethrex is the fastest execution client on <code>newPayload</code> and Erigon the slowest, and Besu spends around 200 ms on <code>forkchoiceUpdated</code> while it is a single-digit or low-double-digit call for the rest. Almost nothing else does. The middle of the field, Geth against Nethermind against Besu, permutes depending on which client you ask. The reason is not the metric definition, and it is not the hardware either. At a fixed version, the same execution client's own internal timer varies by 160 ms depending on which consensus client is driving it, on machines whose load and database size are indistinguishable. That is larger than the margins we would be ranking on.</p>
<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>Read this first</div><div class="admonitionContent_BuS1"><ul>
<li class=""><strong>All three consensus clients time the engine API.</strong> Prysm publishes <code>new_payload_v1_latency_milliseconds</code> and <code>forkchoice_updated_v1_latency_milliseconds</code>. Lighthouse publishes <code>execution_layer_request_times{method="new_payload"|"forkchoice_updated"}</code>, and Nimbus publishes <code>engine_api_request_duration_seconds{request="newPayload"|"forkchoiceUpdated"}</code>, all as complete histograms at about one entry per slot. That is more overlap than we assumed when this series started, and the first two editions read differently as a result. They stand as published; we will put every client's instrumentation side by side, and say plainly what we got wrong along the way, in the finale where that comparison belongs.</li>
<li class=""><strong>No consensus client can see an execution client's internal work.</strong> The engine API returns no timing, so every consensus-side number, including Lighthouse's <code>beacon_block_delay_execution_time</code>, is a wall clock around the client's own engine call. Where clients differ is how much of the call they bracket, which is worth 13 to 76 ms on our fleet, not the hundreds of milliseconds that separate host from host.</li>
<li class=""><strong>Cross-pairing rankings inside about 100 ms are not reliable, including ours.</strong> At a fixed execution-client version, <code>nethermind_new_payload_execution_time</code> reads 195 ms under one consensus client and 355 ms under another. That is not a hardware story: the six machines sit in the same rack with sub-millisecond ping, run 5 to 7% CPU, 5 to 7% disk utilisation and databases within 0.1% of the same size. Comparing two execution clients that were driven by different consensus clients inherits that 160 ms spread, which is why we report the extremes and Besu's <code>forkchoiceUpdated</code> and decline to rank the middle.</li>
<li class=""><strong>Reth is excluded, for the third edition running.</strong> Three independent signals agree: Prysm logged zero <code>VALID</code> payload responses from it against 40,556 optimistic ones, its own <code>reth_sync_checkpoint</code> puts the Execution stage at block 16,340,084 while the chain was past 25.6M, and its container log shows no canonical block commit in the window. It was mid staged-sync, so its fast-looking latency is a <code>SYNCING</code> artifact. See <a class="" href="https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026">the sync-speed census</a>.</li>
<li class=""><strong>Coverage is complete, tail figures are interpolated.</strong> Prysm recorded about 21,565 <code>newPayload</code> and 21,562 <code>forkchoiceUpdated</code> calls per pairing across 21,600 slots. Means and counts are exact. The <code>newPayload</code> buckets stop at 4,000 ms, so 99th percentiles are bucket-interpolated and approximate.</li>
<li class=""><strong>One metric that looks like the outcome is not.</strong> <code>attestation_inclusion_delay_slots</code> returned 3.59 slots for all five pairings, identical to three decimals, because it measures the inclusion delay of attestations in the blocks the node processes, a network-wide property. It cannot separate execution clients.</li>
<li class=""><strong>Window and versions.</strong> Three days, 2026-07-24 to 2026-07-27, Prysm v7.1.7 (Lighthouse v8.2.1 and Nimbus v26.7.0 for the cross-checks) paired with Geth v1.17.4, Nethermind 1.39.2, Besu 26.7.0, Erigon v3.5.2 and Ethrex 22.0.0, on NDC2 bare metal in Vienna. Every execution client was confirmed at the chain tip from its own container logs at both ends of the window.</li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-prysm-measures">What Prysm measures<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-prysm#what-prysm-measures" class="hash-link" aria-label="Direct link to What Prysm measures" title="Direct link to What Prysm measures" translate="no">​</a></h2>
<p>Prysm times both engine calls at one entry per slot, with <code>newPayload</code> buckets running from 25 ms to 4,000 ms, which brackets the range these calls live in. Over the window:</p>
<p><img decoding="async" loading="lazy" alt="newPayload latency per execution client under Prysm: mean from 171 ms for Ethrex to 516 ms for Erigon, with 90th percentiles from 407 ms to 1,136 ms" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDQ4MCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNDgwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTQiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjciIGZvbnQtd2VpZ2h0PSI3MDAiPm5ld1BheWxvYWQgbGF0ZW5jeSBwZXIgZXhlY3V0aW9uIGNsaWVudCwgdW5kZXIgUHJ5c208L3RleHQ+CiAgPHRleHQgeD0iNDgiIHk9Ijg0IiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE2Ij5lbmdpbmUtQVBJIHJvdW5kIHRyaXAgwrcgbWVhbiAoYmFyKSBhbmQgOTB0aCBwZXJjZW50aWxlICh0aWNrKSDCtyBvbmUgbWVhc3VyZW1lbnQgcGVyIHNsb3QsIDMgZGF5czwvdGV4dD4KCiAgPCEtLSBsZWdlbmQgLS0+CiAgPHJlY3QgeD0iNzcwIiB5PSI0MCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPjx0ZXh0IHg9Ijc5MiIgeT0iNTMiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTQiPm1lYW48L3RleHQ+CiAgPGxpbmUgeDE9Ijg2NiIgeTE9IjQwIiB4Mj0iODY2IiB5Mj0iNTYiIHN0cm9rZT0iI2ZkZTY4YSIgc3Ryb2tlLXdpZHRoPSIzIi8+PHRleHQgeD0iODc2IiB5PSI1MyIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCI+OTB0aCBwZXJjZW50aWxlPC90ZXh0PgoKICA8IS0tIGF4aXM6IHgwPTMwMCwgMC4uMTIwMG1zIC0+IDMwMC4uMTEwMCAoMC42NjY3IHB4L21zKSAtLT4KICA8ZyBzdHJva2U9IiMxYzI2NTQiIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8bGluZSB4MT0iNDY2LjciIHkxPSIxMTIiIHgyPSI0NjYuNyIgeTI9IjQwNCIvPgogICAgPGxpbmUgeDE9IjYzMy4zIiB5MT0iMTEyIiB4Mj0iNjMzLjMiIHkyPSI0MDQiLz4KICAgIDxsaW5lIHgxPSI4MDAiIHkxPSIxMTIiIHgyPSI4MDAiIHkyPSI0MDQiLz4KICAgIDxsaW5lIHgxPSI5NjYuNyIgeTE9IjExMiIgeDI9Ijk2Ni43IiB5Mj0iNDA0Ii8+CiAgPC9nPgogIDxnIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJtaWRkbGUiPgogICAgPHRleHQgeD0iMzAwIiB5PSI0MjYiPjA8L3RleHQ+PHRleHQgeD0iNDY2LjciIHk9IjQyNiI+MjUwIG1zPC90ZXh0Pjx0ZXh0IHg9IjYzMy4zIiB5PSI0MjYiPjUwMCBtczwvdGV4dD48dGV4dCB4PSI4MDAiIHk9IjQyNiI+NzUwIG1zPC90ZXh0Pjx0ZXh0IHg9Ijk2Ni43IiB5PSI0MjYiPjEwMDAgbXM8L3RleHQ+CiAgPC9nPgoKICA8IS0tIEV0aHJleCBtZWFuIDE3MSAoMTE0LjApIHA5MCA0MDcgKDI3MS4zKSAtLT4KICA8dGV4dCB4PSIyODgiIHk9IjE0NiIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxNiIgdGV4dC1hbmNob3I9ImVuZCIgZm9udC13ZWlnaHQ9IjYwMCI+RXRocmV4PC90ZXh0PgogIDxyZWN0IHg9IjMwMCIgeT0iMTI4IiB3aWR0aD0iMTE0LjAiIGhlaWdodD0iMjgiIHJ4PSIzIiBmaWxsPSIjNzk4YmZmIi8+CiAgPHRleHQgeD0iNDI0IiB5PSIxNDciIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTQiPjE3MSBtczwvdGV4dD4KICA8bGluZSB4MT0iNTcxLjMiIHkxPSIxMjQiIHgyPSI1NzEuMyIgeTI9IjE2MCIgc3Ryb2tlPSIjZmRlNjhhIiBzdHJva2Utd2lkdGg9IjMiLz4KICA8dGV4dCB4PSI1NzEuMyIgeT0iMTc2IiBmaWxsPSIjOGU5YmJkIiBmb250LXNpemU9IjEyIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj40MDc8L3RleHQ+CgogIDwhLS0gR2V0aCBtZWFuIDMyNiAoMjE3LjMpIHA5MCA4MjIgKDU0OC4wKSAtLT4KICA8dGV4dCB4PSIyODgiIHk9IjIxMiIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxNiIgdGV4dC1hbmNob3I9ImVuZCIgZm9udC13ZWlnaHQ9IjYwMCI+R2V0aDwvdGV4dD4KICA8cmVjdCB4PSIzMDAiIHk9IjE5NCIgd2lkdGg9IjIxNy4zIiBoZWlnaHQ9IjI4IiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPgogIDx0ZXh0IHg9IjUyNyIgeT0iMjEzIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0Ij4zMjYgbXM8L3RleHQ+CiAgPGxpbmUgeDE9Ijg0OC4wIiB5MT0iMTkwIiB4Mj0iODQ4LjAiIHkyPSIyMjYiIHN0cm9rZT0iI2ZkZTY4YSIgc3Ryb2tlLXdpZHRoPSIzIi8+CiAgPHRleHQgeD0iODQ4LjAiIHk9IjI0MiIgZmlsbD0iIzhlOWJiZCIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+ODIyPC90ZXh0PgoKICA8IS0tIE5ldGhlcm1pbmQgbWVhbiAzNzMgKDI0OC43KSBwOTAgOTYzICg2NDIuMCkgLS0+CiAgPHRleHQgeD0iMjg4IiB5PSIyNzgiIGZpbGw9IiNlMmU4ZjQiIGZvbnQtc2l6ZT0iMTYiIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI2MDAiPk5ldGhlcm1pbmQ8L3RleHQ+CiAgPHJlY3QgeD0iMzAwIiB5PSIyNjAiIHdpZHRoPSIyNDguNyIgaGVpZ2h0PSIyOCIgcng9IjMiIGZpbGw9IiM3OThiZmYiLz4KICA8dGV4dCB4PSI1NTgiIHk9IjI3OSIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCI+MzczIG1zPC90ZXh0PgogIDxsaW5lIHgxPSI5NDIuMCIgeTE9IjI1NiIgeDI9Ijk0Mi4wIiB5Mj0iMjkyIiBzdHJva2U9IiNmZGU2OGEiIHN0cm9rZS13aWR0aD0iMyIvPgogIDx0ZXh0IHg9Ijk0Mi4wIiB5PSIzMDgiIGZpbGw9IiM4ZTliYmQiIGZvbnQtc2l6ZT0iMTIiIHRleHQtYW5jaG9yPSJtaWRkbGUiPjk2MzwvdGV4dD4KCiAgPCEtLSBCZXN1IG1lYW4gNDQyICgyOTQuNykgcDkwIDkzNyAoNjI0LjcpIC0tPgogIDx0ZXh0IHg9IjI4OCIgeT0iMzQ0IiBmaWxsPSIjZTJlOGY0IiBmb250LXNpemU9IjE2IiB0ZXh0LWFuY2hvcj0iZW5kIiBmb250LXdlaWdodD0iNjAwIj5CZXN1PC90ZXh0PgogIDxyZWN0IHg9IjMwMCIgeT0iMzI2IiB3aWR0aD0iMjk0LjciIGhlaWdodD0iMjgiIHJ4PSIzIiBmaWxsPSIjNzk4YmZmIi8+CiAgPHRleHQgeD0iNjA1IiB5PSIzNDUiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTQiPjQ0MiBtczwvdGV4dD4KICA8bGluZSB4MT0iOTI0LjciIHkxPSIzMjIiIHgyPSI5MjQuNyIgeTI9IjM1OCIgc3Ryb2tlPSIjZmRlNjhhIiBzdHJva2Utd2lkdGg9IjMiLz4KICA8dGV4dCB4PSI5MjQuNyIgeT0iMzc0IiBmaWxsPSIjOGU5YmJkIiBmb250LXNpemU9IjEyIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj45Mzc8L3RleHQ+CgogIDwhLS0gRXJpZ29uIG1lYW4gNTE2ICgzNDQuMCkgcDkwIDExMzYgKDc1Ny4zKSAtLT4KICA8dGV4dCB4PSIyODgiIHk9IjM5NiIgZmlsbD0iI2ZiOTIzYyIgZm9udC1zaXplPSIxNiIgdGV4dC1hbmNob3I9ImVuZCIgZm9udC13ZWlnaHQ9IjcwMCI+RXJpZ29uPC90ZXh0PgogIDxyZWN0IHg9IjMwMCIgeT0iMzc4IiB3aWR0aD0iMzQ0LjAiIGhlaWdodD0iMjgiIHJ4PSIzIiBmaWxsPSIjZjk3MzE2Ii8+CiAgPHRleHQgeD0iNjU1IiB5PSIzOTciIGZpbGw9IiNmYjkyM2MiIGZvbnQtc2l6ZT0iMTQiIGZvbnQtd2VpZ2h0PSI2MDAiPjUxNiBtczwvdGV4dD4KICA8bGluZSB4MT0iMTA1Ny4zIiB5MT0iMzc0IiB4Mj0iMTA1Ny4zIiB5Mj0iNDEwIiBzdHJva2U9IiNmZGU2OGEiIHN0cm9rZS13aWR0aD0iMyIvPgogIDx0ZXh0IHg9IjEwNTcuMyIgeT0iMzY4IiBmaWxsPSIjZmRlNjhhIiBmb250LXNpemU9IjEyIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj4xMTM2PC90ZXh0PgoKICA8dGV4dCB4PSI0OCIgeT0iNDUyIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE1Ij4zLjB4IHNwcmVhZCBvbiB0aGUgbWVhbi4gRXRocmV4IGZhc3Rlc3QgYW5kIEVyaWdvbiBzbG93ZXN0IHJlcHJvZHVjZXMgcGFydCBvbmUsIHVuZGVyIGEgZGlmZmVyZW50IGNvbnNlbnN1cyBjbGllbnQgYW5kIG5ld2VyIHZlcnNpb25zLjwvdGV4dD4KICA8dGV4dCB4PSIxMTUyIiB5PSI0NTIiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiIHRleHQtYW5jaG9yPSJlbmQiPmRvY3Muc3RlcmV1bWxhYnMuY29tPC90ZXh0PgogIDx0ZXh0IHg9IjQ4IiB5PSI0NzIiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiPlJldGggZXhjbHVkZWQ6IGl0IHdhcyBtaWQgc3RhZ2VkLXN5bmMgKHplcm8gVkFMSUQgcGF5bG9hZCByZXNwb25zZXMpLCBzbyBpdHMgbGF0ZW5jeSBpcyBhIFNZTkNJTkcgYXJ0aWZhY3QuPC90ZXh0Pgo8L3N2Zz4K" width="1200" height="480" class="img_ev3q"></p>
<table><thead><tr><th>Execution client</th><th>Mean</th><th>90th pct</th><th>99th pct*</th></tr></thead><tbody><tr><td><strong>Ethrex</strong> 22.0.0</td><td>171 ms</td><td>407 ms</td><td>~1.94 s</td></tr><tr><td><strong>Geth</strong> v1.17.4</td><td>326 ms</td><td>822 ms</td><td>~2.30 s</td></tr><tr><td><strong>Nethermind</strong> 1.39.2</td><td>373 ms</td><td>963 ms</td><td>~3.16 s</td></tr><tr><td><strong>Besu</strong> 26.7.0</td><td>442 ms</td><td>937 ms</td><td>~3.04 s</td></tr><tr><td><strong>Erigon</strong> v3.5.2</td><td>516 ms</td><td>1,136 ms</td><td>~3.30 s</td></tr></tbody></table>
<p>*bucket-interpolated, since the top finite bucket is 4,000 ms.</p>
<p>On an average block even the slowest of these fits inside the budget: Erigon's 516 ms is about 13% of the 4-second attestation deadline against Ethrex's 4%. The tail is what bites, and at the 99th percentile every client is into the seconds, the same mechanism part one found. Stack a 3-second tail onto a 1.8-second arrival and the slot is gone.</p>
<p>Read on its own, that table looks like a ranking. The rest of this post is about why only its first and last rows are one.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="three-instruments-one-question">Three instruments, one question<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-prysm#three-instruments-one-question" class="hash-link" aria-label="Direct link to Three instruments, one question" title="Direct link to Three instruments, one question" translate="no">​</a></h2>
<p>Because all three clients publish a complete per-slot histogram of the same engine call, and because our fleet runs each consensus client against every execution client, the same question can be asked three times over the same three days on identical execution-client versions. The only thing that changes is which consensus client is holding the stopwatch and driving the execution client.</p>
<p><img decoding="async" loading="lazy" alt="The same newPayload round trip measured by three consensus clients: Ethrex is fastest and Erigon slowest under all three, while Geth, Nethermind and Besu permute between instruments" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDUyMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNTIwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTIiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjciIGZvbnQtd2VpZ2h0PSI3MDAiPlRoZSBzYW1lIGVuZ2luZSBjYWxsLCBtZWFzdXJlZCBieSB0aHJlZSBjb25zZW5zdXMgY2xpZW50czwvdGV4dD4KICA8dGV4dCB4PSI0OCIgeT0iODIiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTYiPm5ld1BheWxvYWQgcm91bmQgdHJpcCDCtyBpZGVudGljYWwgZXhlY3V0aW9uLWNsaWVudCB2ZXJzaW9ucywgc2FtZSB0aHJlZSBkYXlzLCBhYm91dCAyMSw1MDAgb2JzZXJ2YXRpb25zIGVhY2g8L3RleHQ+CgogIDwhLS0gY29sdW1uIGhlYWRlcnMgLS0+CiAgPHRleHQgeD0iMzUwIiB5PSIxMjgiIGZpbGw9IiNlMmU4ZjQiIGZvbnQtc2l6ZT0iMTciIGZvbnQtd2VpZ2h0PSI3MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPkxpZ2h0aG91c2U8L3RleHQ+CiAgPHRleHQgeD0iNjQwIiB5PSIxMjgiIGZpbGw9IiNlMmU4ZjQiIGZvbnQtc2l6ZT0iMTciIGZvbnQtd2VpZ2h0PSI3MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPk5pbWJ1czwvdGV4dD4KICA8dGV4dCB4PSI5MzAiIHk9IjEyOCIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxNyIgZm9udC13ZWlnaHQ9IjcwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+UHJ5c208L3RleHQ+CiAgPHRleHQgeD0iMzUwIiB5PSIxNDYiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTMiIHRleHQtYW5jaG9yPSJtaWRkbGUiPml0cyBwYWlyaW5nczwvdGV4dD4KICA8dGV4dCB4PSI2NDAiIHk9IjE0NiIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9Im1pZGRsZSI+aXRzIHBhaXJpbmdzPC90ZXh0PgogIDx0ZXh0IHg9IjkzMCIgeT0iMTQ2IiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5pdHMgcGFpcmluZ3M8L3RleHQ+CgogIDwhLS0gcmFuayBndWlkZXMgLS0+CiAgPGcgc3Ryb2tlPSIjMTYxZTQ0IiBzdHJva2Utd2lkdGg9IjEiPgogICAgPGxpbmUgeDE9IjMwMCIgeTE9IjE5MCIgeDI9Ijk4MCIgeTI9IjE5MCIvPgogICAgPGxpbmUgeDE9IjMwMCIgeTE9IjI1NSIgeDI9Ijk4MCIgeTI9IjI1NSIvPgogICAgPGxpbmUgeDE9IjMwMCIgeTE9IjMyMCIgeDI9Ijk4MCIgeTI9IjMyMCIvPgogICAgPGxpbmUgeDE9IjMwMCIgeTE9IjM4NSIgeDI9Ijk4MCIgeTI9IjM4NSIvPgogICAgPGxpbmUgeDE9IjMwMCIgeTE9IjQ1MCIgeDI9Ijk4MCIgeTI9IjQ1MCIvPgogIDwvZz4KICA8ZyBmaWxsPSIjNTQ2MDdkIiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0iZW5kIj4KICAgIDx0ZXh0IHg9IjI4OCIgeT0iMTk1Ij5mYXN0ZXN0PC90ZXh0PgogICAgPHRleHQgeD0iMjg4IiB5PSIyNjAiPjJuZDwvdGV4dD4KICAgIDx0ZXh0IHg9IjI4OCIgeT0iMzI1Ij4zcmQ8L3RleHQ+CiAgICA8dGV4dCB4PSIyODgiIHk9IjM5MCI+NHRoPC90ZXh0PgogICAgPHRleHQgeD0iMjg4IiB5PSI0NTUiPnNsb3dlc3Q8L3RleHQ+CiAgPC9nPgoKICA8IS0tIEV0aHJleDogcmFuayAxLDEsMSAtLT4KICA8cG9seWxpbmUgcG9pbnRzPSIzNTAsMTkwIDY0MCwxOTAgOTMwLDE5MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMjJjNTVlIiBzdHJva2Utd2lkdGg9IjQiLz4KICA8Y2lyY2xlIGN4PSIzNTAiIGN5PSIxOTAiIHI9IjciIGZpbGw9IiMyMmM1NWUiLz48Y2lyY2xlIGN4PSI2NDAiIGN5PSIxOTAiIHI9IjciIGZpbGw9IiMyMmM1NWUiLz48Y2lyY2xlIGN4PSI5MzAiIGN5PSIxOTAiIHI9IjciIGZpbGw9IiMyMmM1NWUiLz4KICA8dGV4dCB4PSIzNTAiIHk9IjE3NyIgZmlsbD0iIzg2ZWZhYyIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9Im1pZGRsZSI+MTM5PC90ZXh0PgogIDx0ZXh0IHg9IjY0MCIgeT0iMTc3IiBmaWxsPSIjODZlZmFjIiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj4yMjU8L3RleHQ+CiAgPHRleHQgeD0iOTMwIiB5PSIxNzciIGZpbGw9IiM4NmVmYWMiIGZvbnQtc2l6ZT0iMTMiIHRleHQtYW5jaG9yPSJtaWRkbGUiPjE3MTwvdGV4dD4KICA8dGV4dCB4PSIxMDAwIiB5PSIxOTUiIGZpbGw9IiM4NmVmYWMiIGZvbnQtc2l6ZT0iMTUiIGZvbnQtd2VpZ2h0PSI3MDAiPkV0aHJleDwvdGV4dD4KCiAgPCEtLSBOZXRoZXJtaW5kOiByYW5rIDIsNCwzIC0tPgogIDxwb2x5bGluZSBwb2ludHM9IjM1MCwyNTUgNjQwLDM4NSA5MzAsMzIwIiBmaWxsPSJub25lIiBzdHJva2U9IiNmZGU2OGEiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtZGFzaGFycmF5PSI2IDQiLz4KICA8Y2lyY2xlIGN4PSIzNTAiIGN5PSIyNTUiIHI9IjYiIGZpbGw9IiNmZGU2OGEiLz48Y2lyY2xlIGN4PSI2NDAiIGN5PSIzODUiIHI9IjYiIGZpbGw9IiNmZGU2OGEiLz48Y2lyY2xlIGN4PSI5MzAiIGN5PSIzMjAiIHI9IjYiIGZpbGw9IiNmZGU2OGEiLz4KICA8dGV4dCB4PSIzNTAiIHk9IjI0MiIgZmlsbD0iI2ZkZTY4YSIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9Im1pZGRsZSI+Mjc1PC90ZXh0PgogIDx0ZXh0IHg9IjY2MiIgeT0iMzkwIiBmaWxsPSIjZmRlNjhhIiBmb250LXNpemU9IjEzIj4zNTk8L3RleHQ+CiAgPHRleHQgeD0iOTUyIiB5PSIzMjUiIGZpbGw9IiNmZGU2OGEiIGZvbnQtc2l6ZT0iMTMiPjM3MzwvdGV4dD4KCiAgPCEtLSBHZXRoOiByYW5rIDMsMiwyIC0tPgogIDxwb2x5bGluZSBwb2ludHM9IjM1MCwzMjAgNjQwLDI1NSA5MzAsMjU1IiBmaWxsPSJub25lIiBzdHJva2U9IiM3OThiZmYiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtZGFzaGFycmF5PSI2IDQiLz4KICA8Y2lyY2xlIGN4PSIzNTAiIGN5PSIzMjAiIHI9IjYiIGZpbGw9IiM3OThiZmYiLz48Y2lyY2xlIGN4PSI2NDAiIGN5PSIyNTUiIHI9IjYiIGZpbGw9IiM3OThiZmYiLz48Y2lyY2xlIGN4PSI5MzAiIGN5PSIyNTUiIHI9IjYiIGZpbGw9IiM3OThiZmYiLz4KICA8dGV4dCB4PSIzNTAiIHk9IjM0MCIgZmlsbD0iIzc5OGJmZiIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9Im1pZGRsZSI+MzExPC90ZXh0PgogIDx0ZXh0IHg9IjY2MiIgeT0iMjQ4IiBmaWxsPSIjNzk4YmZmIiBmb250LXNpemU9IjEzIj4zMzg8L3RleHQ+CiAgPHRleHQgeD0iOTUyIiB5PSIyNDgiIGZpbGw9IiM3OThiZmYiIGZvbnQtc2l6ZT0iMTMiPjMyNjwvdGV4dD4KCiAgPCEtLSBCZXN1OiByYW5rIDQsMyw0IC0tPgogIDxwb2x5bGluZSBwb2ludHM9IjM1MCwzODUgNjQwLDMyMCA5MzAsMzg1IiBmaWxsPSJub25lIiBzdHJva2U9IiNjNGI1ZmQiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtZGFzaGFycmF5PSI2IDQiLz4KICA8Y2lyY2xlIGN4PSIzNTAiIGN5PSIzODUiIHI9IjYiIGZpbGw9IiNjNGI1ZmQiLz48Y2lyY2xlIGN4PSI2NDAiIGN5PSIzMjAiIHI9IjYiIGZpbGw9IiNjNGI1ZmQiLz48Y2lyY2xlIGN4PSI5MzAiIGN5PSIzODUiIHI9IjYiIGZpbGw9IiNjNGI1ZmQiLz4KICA8dGV4dCB4PSIzNTAiIHk9IjQwNSIgZmlsbD0iI2M0YjVmZCIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9Im1pZGRsZSI+NDAzPC90ZXh0PgogIDx0ZXh0IHg9IjY2MiIgeT0iMzEzIiBmaWxsPSIjYzRiNWZkIiBmb250LXNpemU9IjEzIj4zNDM8L3RleHQ+CiAgPHRleHQgeD0iOTUyIiB5PSI0MDUiIGZpbGw9IiNjNGI1ZmQiIGZvbnQtc2l6ZT0iMTMiPjQ0MjwvdGV4dD4KCiAgPCEtLSBFcmlnb246IHJhbmsgNSw1LDUgLS0+CiAgPHBvbHlsaW5lIHBvaW50cz0iMzUwLDQ1MCA2NDAsNDUwIDkzMCw0NTAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2Y5NzMxNiIgc3Ryb2tlLXdpZHRoPSI0Ii8+CiAgPGNpcmNsZSBjeD0iMzUwIiBjeT0iNDUwIiByPSI3IiBmaWxsPSIjZjk3MzE2Ii8+PGNpcmNsZSBjeD0iNjQwIiBjeT0iNDUwIiByPSI3IiBmaWxsPSIjZjk3MzE2Ii8+PGNpcmNsZSBjeD0iOTMwIiBjeT0iNDUwIiByPSI3IiBmaWxsPSIjZjk3MzE2Ii8+CiAgPHRleHQgeD0iMzUwIiB5PSI0NzAiIGZpbGw9IiNmYjkyM2MiIGZvbnQtc2l6ZT0iMTMiIHRleHQtYW5jaG9yPSJtaWRkbGUiPjUwMzwvdGV4dD4KICA8dGV4dCB4PSI2NDAiIHk9IjQ3MCIgZmlsbD0iI2ZiOTIzYyIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9Im1pZGRsZSI+NTM1PC90ZXh0PgogIDx0ZXh0IHg9IjkzMCIgeT0iNDcwIiBmaWxsPSIjZmI5MjNjIiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj41MTY8L3RleHQ+CiAgPHRleHQgeD0iMTAwMCIgeT0iNDU1IiBmaWxsPSIjZmI5MjNjIiBmb250LXNpemU9IjE1IiBmb250LXdlaWdodD0iNzAwIj5Fcmlnb248L3RleHQ+CgogIDwhLS0gbWlkZGxlIGxlZ2VuZCAtLT4KICA8dGV4dCB4PSIxMDAwIiB5PSIyOTAiIGZpbGw9IiM4ZTliYmQiIGZvbnQtc2l6ZT0iMTMiPkdldGgsIE5ldGhlcm1pbmQ8L3RleHQ+CiAgPHRleHQgeD0iMTAwMCIgeT0iMzA4IiBmaWxsPSIjOGU5YmJkIiBmb250LXNpemU9IjEzIj5hbmQgQmVzdTogYWxsIHRocmVlPC90ZXh0PgogIDx0ZXh0IHg9IjEwMDAiIHk9IjMyNiIgZmlsbD0iIzhlOWJiZCIgZm9udC1zaXplPSIxMyI+cGVybXV0YXRpb25zIGFwcGVhciw8L3RleHQ+CiAgPHRleHQgeD0iMTAwMCIgeT0iMzQ0IiBmaWxsPSIjOGU5YmJkIiBmb250LXNpemU9IjEzIj5ubyB0d28gaW5zdHJ1bWVudHM8L3RleHQ+CiAgPHRleHQgeD0iMTAwMCIgeT0iMzYyIiBmaWxsPSIjOGU5YmJkIiBmb250LXNpemU9IjEzIj5hZ3JlZTwvdGV4dD4KCiAgPHRleHQgeD0iNDgiIHk9IjQ5OCIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMiI+VmFsdWVzIGluIG1pbGxpc2Vjb25kcy4gRWFjaCBjb25zZW5zdXMgY2xpZW50IGRyaXZlcyBpdHMgb3duIGV4ZWN1dGlvbi1jbGllbnQgc2V0LCBzbyB0aGUgaW5zdHJ1bWVudCBhbmQgdGhlIGRyaXZlciBjaGFuZ2UgdG9nZXRoZXIuIFJldGggZXhjbHVkZWQgKG1pZCBzdGFnZWQtc3luYykuPC90ZXh0PgogIDx0ZXh0IHg9IjExNTIiIHk9IjQ5OCIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9ImVuZCI+ZG9jcy5zdGVyZXVtbGFicy5jb208L3RleHQ+Cjwvc3ZnPgo=" width="1200" height="520" class="img_ev3q"></p>
<table><thead><tr><th>Execution client</th><th>Lighthouse</th><th>Nimbus</th><th>Prysm</th></tr></thead><tbody><tr><td><strong>Ethrex</strong></td><td>139 ms</td><td>225 ms</td><td>171 ms</td></tr><tr><td><strong>Nethermind</strong></td><td>275 ms</td><td>359 ms</td><td>373 ms</td></tr><tr><td><strong>Geth</strong></td><td>311 ms</td><td>338 ms</td><td>326 ms</td></tr><tr><td><strong>Besu</strong></td><td>403 ms</td><td>343 ms</td><td>442 ms</td></tr><tr><td><strong>Erigon</strong></td><td>503 ms</td><td>535 ms</td><td>516 ms</td></tr></tbody></table>
<p>Ethrex is first in all three columns and Erigon last in all three. Those two results are worth trusting: three instruments, three host sets, about 21,500 observations each.</p>
<p>Everything between them moves. Lighthouse orders the middle Nethermind, Geth, Besu. Nimbus orders it Geth, Besu, Nethermind. Prysm orders it Geth, Nethermind, Besu. All three permutations appear, and no two agree.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-the-middle-does-not-rank">Why the middle does not rank<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-prysm#why-the-middle-does-not-rank" class="hash-link" aria-label="Direct link to Why the middle does not rank" title="Direct link to Why the middle does not rank" translate="no">​</a></h2>
<p>It would be convenient to blame the metric definitions, and we nearly did. It does not hold up, for two reasons we can measure.</p>
<p>The definitional effect is small and we can size it without leaving one host. Lighthouse publishes both quantities itself, on the same machine, in the same window: the gauge that brackets its execution step and the histogram of the full engine round trip. Going from one to the other costs 13 ms for Besu, 22 ms for Geth, 34 ms for Nethermind, 42 ms for Ethrex and 76 ms for Erigon. It reorders nothing: Nethermind stays 36 ms ahead of Geth on both of Lighthouse's own rulers, on all three days separately.</p>
<p>What does move is the pairing, and the execution clients measure it themselves. Nethermind 1.39.2 publishes its own internal payload-execution time, a number no consensus client is in the loop for. Across our six pairings, same version, same window:</p>
<p><img decoding="async" loading="lazy" alt="Nethermind 1.39.2&amp;#39;s own internal payload-execution timer under six different consensus clients: 195 ms when driven by Grandine rising to 355 ms under Prysm, an 80 percent spread at fixed version on equally loaded machines" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDUwMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNTAwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTIiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjciIGZvbnQtd2VpZ2h0PSI3MDAiPk9uZSBleGVjdXRpb24gY2xpZW50LCBvbmUgdmVyc2lvbiwgc2l4IGRyaXZlcnM8L3RleHQ+CiAgPHRleHQgeD0iNDgiIHk9IjgyIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE2Ij5OZXRoZXJtaW5kIDEuMzkuMiB0aW1pbmcgaXRzIG93biBwYXlsb2FkIGV4ZWN1dGlvbiDCtyBubyBjb25zZW5zdXMgY2xpZW50IGluIHRoZSBtZWFzdXJlbWVudCDCtyBzYW1lIHRocmVlIGRheXM8L3RleHQ+CgogIDwhLS0gYXhpczogeDA9MzQwLCAxLjY4NCBweC9tcywgMC4uMzgwIC0tPgogIDxnIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIxIj4KICAgIDxsaW5lIHgxPSI1MDguNCIgeTE9IjExMiIgeDI9IjUwOC40IiB5Mj0iMzkyIi8+CiAgICA8bGluZSB4MT0iNjc2LjgiIHkxPSIxMTIiIHgyPSI2NzYuOCIgeTI9IjM5MiIvPgogICAgPGxpbmUgeDE9Ijg0NS4yIiB5MT0iMTEyIiB4Mj0iODQ1LjIiIHkyPSIzOTIiLz4KICA8L2c+CiAgPGcgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+CiAgICA8dGV4dCB4PSIzNDAiIHk9IjQxNCI+MDwvdGV4dD48dGV4dCB4PSI1MDguNCIgeT0iNDE0Ij4xMDAgbXM8L3RleHQ+PHRleHQgeD0iNjc2LjgiIHk9IjQxNCI+MjAwIG1zPC90ZXh0Pjx0ZXh0IHg9Ijg0NS4yIiB5PSI0MTQiPjMwMCBtczwvdGV4dD4KICA8L2c+CgogIDx0ZXh0IHg9IjMyOCIgeT0iMTQ2IiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE1IiB0ZXh0LWFuY2hvcj0iZW5kIj5kcml2ZW4gYnkgR3JhbmRpbmU8L3RleHQ+CiAgPHJlY3QgeD0iMzQwIiB5PSIxMzAiIHdpZHRoPSIzMjguNCIgaGVpZ2h0PSIyNCIgcng9IjMiIGZpbGw9IiM3OThiZmYiLz48dGV4dCB4PSI2ODAiIHk9IjE0OCIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCI+MTk1IG1zPC90ZXh0PgogIDx0ZXh0IHg9IjMyOCIgeT0iMTg4IiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE1IiB0ZXh0LWFuY2hvcj0iZW5kIj5kcml2ZW4gYnkgVGVrdTwvdGV4dD4KICA8cmVjdCB4PSIzNDAiIHk9IjE3MiIgd2lkdGg9IjQwMi41IiBoZWlnaHQ9IjI0IiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPjx0ZXh0IHg9Ijc1NCIgeT0iMTkwIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0Ij4yMzkgbXM8L3RleHQ+CiAgPHRleHQgeD0iMzI4IiB5PSIyMzAiIGZpbGw9IiNmZGU2OGEiIGZvbnQtc2l6ZT0iMTUiIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI3MDAiPmRyaXZlbiBieSBMaWdodGhvdXNlPC90ZXh0PgogIDxyZWN0IHg9IjM0MCIgeT0iMjE0IiB3aWR0aD0iNDQyLjkiIGhlaWdodD0iMjQiIHJ4PSIzIiBmaWxsPSIjZmRlNjhhIi8+PHRleHQgeD0iNzk1IiB5PSIyMzIiIGZpbGw9IiNmZGU2OGEiIGZvbnQtc2l6ZT0iMTQiIGZvbnQtd2VpZ2h0PSI2MDAiPjI2MyBtczwvdGV4dD4KICA8dGV4dCB4PSIzMjgiIHk9IjI3MiIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNSIgdGV4dC1hbmNob3I9ImVuZCI+ZHJpdmVuIGJ5IE5pbWJ1czwvdGV4dD4KICA8cmVjdCB4PSIzNDAiIHk9IjI1NiIgd2lkdGg9IjUyMy43IiBoZWlnaHQ9IjI0IiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPjx0ZXh0IHg9Ijg3NSIgeT0iMjc0IiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0Ij4zMTEgbXM8L3RleHQ+CiAgPHRleHQgeD0iMzI4IiB5PSIzMTQiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTUiIHRleHQtYW5jaG9yPSJlbmQiPmRyaXZlbiBieSBMb2Rlc3RhcjwvdGV4dD4KICA8cmVjdCB4PSIzNDAiIHk9IjI5OCIgd2lkdGg9IjU3NC4yIiBoZWlnaHQ9IjI0IiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPjx0ZXh0IHg9IjkyNiIgeT0iMzE2IiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0Ij4zNDEgbXM8L3RleHQ+CiAgPHRleHQgeD0iMzI4IiB5PSIzNTYiIGZpbGw9IiNmYjkyM2MiIGZvbnQtc2l6ZT0iMTUiIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI3MDAiPmRyaXZlbiBieSBQcnlzbTwvdGV4dD4KICA8cmVjdCB4PSIzNDAiIHk9IjM0MCIgd2lkdGg9IjU5Ny44IiBoZWlnaHQ9IjI0IiByeD0iMyIgZmlsbD0iI2Y5NzMxNiIvPjx0ZXh0IHg9Ijk1MCIgeT0iMzU4IiBmaWxsPSIjZmI5MjNjIiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iNjAwIj4zNTUgbXM8L3RleHQ+CgogIDwhLS0gc3ByZWFkIGJyYWNrZXQgLS0+CiAgPGxpbmUgeDE9IjY2OC40IiB5MT0iMTI4IiB4Mj0iNjY4LjQiIHkyPSIzNjgiIHN0cm9rZT0iIzUwNDZlNSIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1kYXNoYXJyYXk9IjQgNCIvPgogIDxsaW5lIHgxPSI5MzcuOCIgeTE9IjEyOCIgeDI9IjkzNy44IiB5Mj0iMzY4IiBzdHJva2U9IiM1MDQ2ZTUiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtZGFzaGFycmF5PSI0IDQiLz4KICA8bGluZSB4MT0iNjY4LjQiIHkxPSIzNzgiIHgyPSI5MzcuOCIgeTI9IjM3OCIgc3Ryb2tlPSIjOGI4ZmY1IiBzdHJva2Utd2lkdGg9IjIiLz4KICA8dGV4dCB4PSI4MDMiIHk9IjM5NiIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9Im1pZGRsZSI+MTYwIG1zLCBvciA4MCUsIGF0IGZpeGVkIHZlcnNpb248L3RleHQ+CgogIDwhLS0gbWFjaGluZXMtYXJlLWVxdWFsIGJveCAtLT4KICA8cmVjdCB4PSI5ODUiIHk9IjEyNiIgd2lkdGg9IjE2OCIgaGVpZ2h0PSIyMzgiIHJ4PSI4IiBmaWxsPSIjMWUyOTNiIiBzdHJva2U9IiMzMzQxNTUiIHN0cm9rZS13aWR0aD0iMSIvPgogIDx0ZXh0IHg9IjEwNjkiIHk9IjE1MiIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZm9udC13ZWlnaHQ9IjcwMCI+Tm90IHRoZSBtYWNoaW5lPC90ZXh0PgogIDx0ZXh0IHg9IjEwNjkiIHk9IjE3NiIgZmlsbD0iIzg2ZWZhYyIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9Im1pZGRsZSI+Q1BVIDUuMiB0byA2LjclPC90ZXh0PgogIDx0ZXh0IHg9IjEwNjkiIHk9IjE5OCIgZmlsbD0iIzg2ZWZhYyIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9Im1pZGRsZSI+ZGlzayA1LjEgdG8gNy4zJTwvdGV4dD4KICA8dGV4dCB4PSIxMDY5IiB5PSIyMjAiIGZpbGw9IiM4NmVmYWMiIGZvbnQtc2l6ZT0iMTMiIHRleHQtYW5jaG9yPSJtaWRkbGUiPnJlYWQgMS44IHRvIDIuMSBNQi9zPC90ZXh0PgogIDx0ZXh0IHg9IjEwNjkiIHk9IjI0MiIgZmlsbD0iIzg2ZWZhYyIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9Im1pZGRsZSI+Y2FjaGUgOC45IHRvIDkuOSBHaUI8L3RleHQ+CiAgPHRleHQgeD0iMTA2OSIgeT0iMjY0IiBmaWxsPSIjODZlZmFjIiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5EQiB3aXRoaW4gMC4xJTwvdGV4dD4KICA8dGV4dCB4PSIxMDY5IiB5PSIyOTQiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTIiIHRleHQtYW5jaG9yPSJtaWRkbGUiPmlkZW50aWNhbCAxMi1jb3JlPC90ZXh0PgogIDx0ZXh0IHg9IjEwNjkiIHk9IjMxMiIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+YmFyZSBtZXRhbCwgb25lIHJhY2ssPC90ZXh0PgogIDx0ZXh0IHg9IjEwNjkiIHk9IjMzMCIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+c3ViLW1pbGxpc2Vjb25kIHBpbmc8L3RleHQ+CiAgPHRleHQgeD0iMTA2OSIgeT0iMzU2IiBmaWxsPSIjZmNhNWE1IiBmb250LXNpemU9IjEyIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5sb2FkIG9yZGVyIGRvZXMgbm90PC90ZXh0PgogIDx0ZXh0IHg9IjEwNjkiIHk9IjM3MiIgZmlsbD0iI2ZjYTVhNSIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+bWF0Y2ggbGF0ZW5jeSBvcmRlcjwvdGV4dD4KCiAgPHRleHQgeD0iNDgiIHk9IjQ1MiIgZmlsbD0iI2ZkZTY4YSIgZm9udC1zaXplPSIxNSI+VGhlIGNvbnNlbnN1cyBjbGllbnQgZHJpdmluZyBpdCBtb3ZlcyB0aGUgc2FtZSBidWlsZCBieSA4MCUsIG9uIG1hY2hpbmVzIHRoYXQgYXJlIGVxdWFsbHkgaWRsZSBhbmQgZXF1YWxseSBmdWxsLjwvdGV4dD4KICA8dGV4dCB4PSI0OCIgeT0iNDc0IiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEyIj5uZXRoZXJtaW5kX25ld19wYXlsb2FkX2V4ZWN1dGlvbl90aW1lLCBlY192ZXJzaW9uIDEuMzkuMiwgNCwzMjAgc2FtcGxlcyBwZXIgcGFpcmluZy4gTWVjaGFuaXNtIG9wZW46IGhhbmRvdmVyIHRpbWluZyBhZ2FpbnN0IHNwZWN1bGF0aXZlIGV4ZWN1dGlvbiBpcyB0aGUgbmV4dCB0aGluZyB0byB0ZXN0LjwvdGV4dD4KICA8dGV4dCB4PSIxMTUyIiB5PSI0NzQiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiIHRleHQtYW5jaG9yPSJlbmQiPmRvY3Muc3RlcmV1bWxhYnMuY29tPC90ZXh0Pgo8L3N2Zz4K" width="1200" height="500" class="img_ev3q"></p>
<table><thead><tr><th>Driven by</th><th>Nethermind's own <code>newPayload</code> time</th></tr></thead><tbody><tr><td>Grandine</td><td>195 ms</td></tr><tr><td>Teku</td><td>239 ms</td></tr><tr><td>Lighthouse</td><td>263 ms</td></tr><tr><td>Nimbus</td><td>311 ms</td></tr><tr><td>Lodestar</td><td>341 ms</td></tr><tr><td>Prysm</td><td>355 ms</td></tr></tbody></table>
<p>One client, one version, one metric, no consensus client in the measurement, spanning 160 ms, or 80% of the fastest value.</p>
<p>The obvious suspect is the machine, and we checked it, because on this fleet it is checkable. The six hosts are identical 12-core bare metal in the same rack with sub-millisecond ping between them. Over this window they ran 5.2 to 6.7% CPU and 5.1 to 7.3% disk utilisation, so neither resource was anywhere near saturation on any of them. They read 1.8 to 2.1 MB/s from disk, held 8.9 to 9.9 GiB of page cache, and their databases are within 0.1% of the same size, 1.1506 against 1.1516 TiB. Nothing in that spread of load explains an 80% spread in execution time, and the ordering does not follow it: the Lighthouse-paired host is the second least busy and the third slowest.</p>
<p>So the number tracks which consensus client is asking, not the box it runs on. What we cannot do from timing data alone is say why. The candidate we would test next is handover timing against speculative execution: these clients pre-warm state from the mempool before the payload arrives, so a consensus client that hands the block over at a slightly different moment, or that pipelines <code>newPayload</code> differently against its blob and forkchoice traffic, leaves a different amount of that work already done. That is a hypothesis, not a result, and it is the kind of thing the next editions can test now that we know to look.</p>
<p>For anyone reading a client comparison, including this one, the practical consequence does not depend on the mechanism. Two execution clients are only comparable when the same consensus client drove both of them. That is why the table in the previous section is a fair ranking under Prysm and not a fair ranking full stop, and why differences of the size of Ethrex against Erigon, a factor of three, survive changing the driver while differences of 10 or 15% do not.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-engine-call-almost-nobody-looks-at">The engine call almost nobody looks at<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-prysm#the-engine-call-almost-nobody-looks-at" class="hash-link" aria-label="Direct link to The engine call almost nobody looks at" title="Direct link to The engine call almost nobody looks at" translate="no">​</a></h2>
<p>Every slot, a consensus client makes at least two engine calls: <code>newPayload</code> to hand over the block and <code>forkchoiceUpdated</code> to name the head. Dashboards, benchmarks and the first two editions of this series all watch the first one. The second is where the one client-specific anomaly on our fleet lives, and unlike the middle-of-field ordering, it survives triangulation:</p>
<p><img decoding="async" loading="lazy" alt="forkchoiceUpdated latency per execution client under three consensus clients: Besu costs about 200 ms under all three instruments while the other four clients vary from 4 ms to 261 ms depending on which client is measuring" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDUyMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNTIwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTIiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjciIGZvbnQtd2VpZ2h0PSI3MDAiPmZvcmtjaG9pY2VVcGRhdGVkLCBtZWFzdXJlZCB0aHJlZSB3YXlzPC90ZXh0PgogIDx0ZXh0IHg9IjQ4IiB5PSI4MiIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxNiI+dGhlIHNlY29uZCBlbmdpbmUgY2FsbCwgYWJvdXQgb25lIHBlciBzbG90IHVuZGVyIGFsbCB0aHJlZSBjb25zZW5zdXMgY2xpZW50cyDCtyBzYW1lIHdpbmRvdywgc2FtZSBleGVjdXRpb24tY2xpZW50IHZlcnNpb25zPC90ZXh0PgoKICA8IS0tIGxlZ2VuZCAtLT4KICA8cmVjdCB4PSI3MDAiIHk9IjQwIiB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHJ4PSIzIiBmaWxsPSIjNTQ2MDdkIi8+PHRleHQgeD0iNzIwIiB5PSI1MiIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxMyI+TGlnaHRob3VzZTwvdGV4dD4KICA8cmVjdCB4PSI4MjAiIHk9IjQwIiB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHJ4PSIzIiBmaWxsPSIjNzk4YmZmIi8+PHRleHQgeD0iODQwIiB5PSI1MiIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxMyI+TmltYnVzPC90ZXh0PgogIDxyZWN0IHg9IjkyMCIgeT0iNDAiIHdpZHRoPSIxNCIgaGVpZ2h0PSIxNCIgcng9IjMiIGZpbGw9IiNmZGU2OGEiLz48dGV4dCB4PSI5NDAiIHk9IjUyIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjEzIj5QcnlzbTwvdGV4dD4KCiAgPCEtLSBheGlzOiB4MD0zODAsIDIuMjE0IHB4L21zIC0tPgogIDxnIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIxIj4KICAgIDxsaW5lIHgxPSI0OTAuNyIgeTE9IjExMiIgeDI9IjQ5MC43IiB5Mj0iNDMwIi8+CiAgICA8bGluZSB4MT0iNjAxLjQiIHkxPSIxMTIiIHgyPSI2MDEuNCIgeTI9IjQzMCIvPgogICAgPGxpbmUgeDE9IjgyMi44IiB5MT0iMTEyIiB4Mj0iODIyLjgiIHkyPSI0MzAiLz4KICA8L2c+CiAgPGcgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9Im1pZGRsZSI+CiAgICA8dGV4dCB4PSIzODAiIHk9IjQ1MiI+MDwvdGV4dD48dGV4dCB4PSI0OTAuNyIgeT0iNDUyIj41MCBtczwvdGV4dD48dGV4dCB4PSI2MDEuNCIgeT0iNDUyIj4xMDAgbXM8L3RleHQ+PHRleHQgeD0iODIyLjgiIHk9IjQ1MiI+MjAwIG1zPC90ZXh0PgogIDwvZz4KCiAgPCEtLSBCZXN1OiAxOTcgLyAxOTMgLyAyMDggLS0+CiAgPHJlY3QgeD0iMzcwIiB5PSIxMjYiIHdpZHRoPSI3MDAiIGhlaWdodD0iNTgiIHJ4PSI2IiBmaWxsPSIjZjk3MzE2IiBvcGFjaXR5PSIwLjEwIi8+CiAgPHRleHQgeD0iMzY4IiB5PSIxNTgiIGZpbGw9IiNmYjkyM2MiIGZvbnQtc2l6ZT0iMTYiIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI3MDAiPkJlc3U8L3RleHQ+CiAgPHJlY3QgeD0iMzgwIiB5PSIxMzIiIHdpZHRoPSI0MzYuMiIgaGVpZ2h0PSIxNSIgcng9IjIiIGZpbGw9IiNmOTczMTYiIG9wYWNpdHk9IjAuNTUiLz48dGV4dCB4PSI4MjQiIHk9IjE0NCIgZmlsbD0iI2ZiOTIzYyIgZm9udC1zaXplPSIxMiI+MTk3PC90ZXh0PgogIDxyZWN0IHg9IjM4MCIgeT0iMTUwIiB3aWR0aD0iNDI3LjMiIGhlaWdodD0iMTUiIHJ4PSIyIiBmaWxsPSIjZjk3MzE2IiBvcGFjaXR5PSIwLjc4Ii8+PHRleHQgeD0iODE1IiB5PSIxNjIiIGZpbGw9IiNmYjkyM2MiIGZvbnQtc2l6ZT0iMTIiPjE5MzwvdGV4dD4KICA8cmVjdCB4PSIzODAiIHk9IjE2OCIgd2lkdGg9IjQ2MC41IiBoZWlnaHQ9IjE1IiByeD0iMiIgZmlsbD0iI2Y5NzMxNiIvPjx0ZXh0IHg9Ijg0OCIgeT0iMTgwIiBmaWxsPSIjZmI5MjNjIiBmb250LXNpemU9IjEyIiBmb250LXdlaWdodD0iNzAwIj4yMDg8L3RleHQ+CiAgPHRleHQgeD0iOTAwIiB5PSIxNjIiIGZpbGw9IiNmZGU2OGEiIGZvbnQtc2l6ZT0iMTQiIGZvbnQtd2VpZ2h0PSI2MDAiPnN0YWJsZSBhY3Jvc3MgYWxsIHRocmVlPC90ZXh0PgoKICA8IS0tIE5ldGhlcm1pbmQ6IDYgLyAyNTUgLyA0IC0tPgogIDx0ZXh0IHg9IjM2OCIgeT0iMjI4IiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE2IiB0ZXh0LWFuY2hvcj0iZW5kIj5OZXRoZXJtaW5kPC90ZXh0PgogIDxyZWN0IHg9IjM4MCIgeT0iMjAyIiB3aWR0aD0iMTMuMyIgaGVpZ2h0PSIxNSIgcng9IjIiIGZpbGw9IiM1NDYwN2QiLz48dGV4dCB4PSI0MDAiIHk9IjIxNCIgZmlsbD0iIzhlOWJiZCIgZm9udC1zaXplPSIxMiI+NjwvdGV4dD4KICA8cmVjdCB4PSIzODAiIHk9IjIyMCIgd2lkdGg9IjU2NC42IiBoZWlnaHQ9IjE1IiByeD0iMiIgZmlsbD0iIzc5OGJmZiIvPjx0ZXh0IHg9Ijk1MiIgeT0iMjMyIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjEyIj4yNTU8L3RleHQ+CiAgPHJlY3QgeD0iMzgwIiB5PSIyMzgiIHdpZHRoPSI4LjkiIGhlaWdodD0iMTUiIHJ4PSIyIiBmaWxsPSIjZmRlNjhhIi8+PHRleHQgeD0iMzk4IiB5PSIyNTAiIGZpbGw9IiM4ZTliYmQiIGZvbnQtc2l6ZT0iMTIiPjQ8L3RleHQ+CgogIDwhLS0gRXRocmV4OiA4IC8gMjYxIC8gNyAtLT4KICA8dGV4dCB4PSIzNjgiIHk9IjI5OCIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNiIgdGV4dC1hbmNob3I9ImVuZCI+RXRocmV4PC90ZXh0PgogIDxyZWN0IHg9IjM4MCIgeT0iMjcyIiB3aWR0aD0iMTcuNyIgaGVpZ2h0PSIxNSIgcng9IjIiIGZpbGw9IiM1NDYwN2QiLz48dGV4dCB4PSI0MDQiIHk9IjI4NCIgZmlsbD0iIzhlOWJiZCIgZm9udC1zaXplPSIxMiI+ODwvdGV4dD4KICA8cmVjdCB4PSIzODAiIHk9IjI5MCIgd2lkdGg9IjU3Ny45IiBoZWlnaHQ9IjE1IiByeD0iMiIgZmlsbD0iIzc5OGJmZiIvPjx0ZXh0IHg9Ijk2NiIgeT0iMzAyIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjEyIj4yNjE8L3RleHQ+CiAgPHJlY3QgeD0iMzgwIiB5PSIzMDgiIHdpZHRoPSIxNS41IiBoZWlnaHQ9IjE1IiByeD0iMiIgZmlsbD0iI2ZkZTY4YSIvPjx0ZXh0IHg9IjQwMiIgeT0iMzIwIiBmaWxsPSIjOGU5YmJkIiBmb250LXNpemU9IjEyIj43PC90ZXh0PgoKICA8IS0tIEdldGg6IDExIC8gNjkgLyAxMCAtLT4KICA8dGV4dCB4PSIzNjgiIHk9IjM2OCIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNiIgdGV4dC1hbmNob3I9ImVuZCI+R2V0aDwvdGV4dD4KICA8cmVjdCB4PSIzODAiIHk9IjM0MiIgd2lkdGg9IjI0LjQiIGhlaWdodD0iMTUiIHJ4PSIyIiBmaWxsPSIjNTQ2MDdkIi8+PHRleHQgeD0iNDExIiB5PSIzNTQiIGZpbGw9IiM4ZTliYmQiIGZvbnQtc2l6ZT0iMTIiPjExPC90ZXh0PgogIDxyZWN0IHg9IjM4MCIgeT0iMzYwIiB3aWR0aD0iMTUyLjgiIGhlaWdodD0iMTUiIHJ4PSIyIiBmaWxsPSIjNzk4YmZmIi8+PHRleHQgeD0iNTQwIiB5PSIzNzIiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTIiPjY5PC90ZXh0PgogIDxyZWN0IHg9IjM4MCIgeT0iMzc4IiB3aWR0aD0iMjIuMSIgaGVpZ2h0PSIxNSIgcng9IjIiIGZpbGw9IiNmZGU2OGEiLz48dGV4dCB4PSI0MDkiIHk9IjM5MCIgZmlsbD0iIzhlOWJiZCIgZm9udC1zaXplPSIxMiI+MTA8L3RleHQ+CgogIDwhLS0gRXJpZ29uOiAxNCAvIDYzIC8gNiAtLT4KICA8dGV4dCB4PSIzNjgiIHk9IjQyMCIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNiIgdGV4dC1hbmNob3I9ImVuZCI+RXJpZ29uPC90ZXh0PgogIDxyZWN0IHg9IjM4MCIgeT0iNDAwIiB3aWR0aD0iMzEuMCIgaGVpZ2h0PSIxMSIgcng9IjIiIGZpbGw9IiM1NDYwN2QiLz48dGV4dCB4PSI0MTgiIHk9IjQxMCIgZmlsbD0iIzhlOWJiZCIgZm9udC1zaXplPSIxMiI+MTQ8L3RleHQ+CiAgPHJlY3QgeD0iMzgwIiB5PSI0MTMiIHdpZHRoPSIxMzkuNSIgaGVpZ2h0PSIxMSIgcng9IjIiIGZpbGw9IiM3OThiZmYiLz48dGV4dCB4PSI1MjciIHk9IjQyMyIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxMiI+NjM8L3RleHQ+CiAgPHJlY3QgeD0iMzgwIiB5PSI0MjYiIHdpZHRoPSIxMy4zIiBoZWlnaHQ9IjExIiByeD0iMiIgZmlsbD0iI2ZkZTY4YSIvPjx0ZXh0IHg9IjQwMCIgeT0iNDM2IiBmaWxsPSIjOGU5YmJkIiBmb250LXNpemU9IjEyIj42PC90ZXh0PgoKICA8dGV4dCB4PSI0OCIgeT0iNDgyIiBmaWxsPSIjZmRlNjhhIiBmb250LXNpemU9IjE1Ij5CZXN1IHBheXMgYWJvdXQgMjAwIG1zIG9uIHRoZSBoZWFkLXVwZGF0ZSBjYWxsIHVuZGVyIGV2ZXJ5IGluc3RydW1lbnQuIFRoZSBvdGhlciBmb3VyIHN3aW5nIGJ5IDQweCBiZXR3ZWVuIGluc3RydW1lbnRzLCBzbyB0aGVpciBudW1iZXJzIGFyZSBub3QgY2xpZW50IHByb3BlcnRpZXMuPC90ZXh0PgogIDx0ZXh0IHg9IjQ4IiB5PSI1MDQiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiPlZhbHVlcyBpbiBtaWxsaXNlY29uZHMsIG1lYW5zIG92ZXIgdGhyZWUgZGF5cywgYWJvdXQgMjEsNTAwIHRvIDIyLDMwMCBjYWxscyBwZXIgcGFpcmluZyBwZXIgaW5zdHJ1bWVudC4gUmV0aCBleGNsdWRlZCAobWlkIHN0YWdlZC1zeW5jKS48L3RleHQ+CiAgPHRleHQgeD0iMTE1MiIgeT0iNTA0IiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEyIiB0ZXh0LWFuY2hvcj0iZW5kIj5kb2NzLnN0ZXJldW1sYWJzLmNvbTwvdGV4dD4KPC9zdmc+Cg==" width="1200" height="520" class="img_ev3q"></p>
<table><thead><tr><th>Execution client</th><th>Lighthouse</th><th>Nimbus</th><th>Prysm</th></tr></thead><tbody><tr><td><strong>Besu</strong></td><td>197 ms</td><td>193 ms</td><td>208 ms</td></tr><tr><td>Erigon</td><td>14 ms</td><td>63 ms</td><td>6 ms</td></tr><tr><td>Geth</td><td>11 ms</td><td>69 ms</td><td>10 ms</td></tr><tr><td>Ethrex</td><td>8 ms</td><td>261 ms</td><td>7 ms</td></tr><tr><td>Nethermind</td><td>6 ms</td><td>255 ms</td><td>4 ms</td></tr></tbody></table>
<p>Besu's row is the flat one: 197, 193, 208 ms, on three instruments and three pairings, at about 21,500 calls each. Under Prysm it is roughly 30x the next client and 443 ms at the 90th percentile against their 23 ms, and the shape of the distribution carries it rather than a few outliers: only 14% of Besu's calls come in under 100 ms, 58% under 200 ms, and just 0.5% exceed a second.</p>
<p>The other four rows are the cautionary tale in miniature. Nethermind's <code>forkchoiceUpdated</code> reads 6 ms under Lighthouse, 4 ms under Prysm and 255 ms under Nimbus. We are not going to pretend to explain that from timing data alone; the call counts are about one per slot under all three, so it is not a difference in how often the call is made. It is a reminder that a number this instrument-dependent is not a client property, and that Besu's stability across the same three instruments is what makes its 200 ms worth reporting.</p>
<p>Why Besu, we can bound but not settle. The same Besu is the one that in <a class="" href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour">our pruning census</a> does storage work on the engine-API hot path, and <code>forkchoiceUpdated</code> is where a client updates its canonical head, so head-update bookkeeping touching storage is the plausible mechanism. We have not lined up individual slow calls against Besu's storage activity, so this is a measured cost without a confirmed cause.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-the-200-ms-does-and-does-not-cost">What the 200 ms does and does not cost<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-prysm#what-the-200-ms-does-and-does-not-cost" class="hash-link" aria-label="Direct link to What the 200 ms does and does not cost" title="Direct link to What the 200 ms does and does not cost" translate="no">​</a></h2>
<p>It is tempting to add the two calls up and crown a winner. We did, in a draft of this post, and the fleet's own data talked us out of it. Summing the means is arithmetically fine, since both histograms carry the same one-per-slot denominator: Besu spends about 650 ms per slot across the two calls Prysm times against Erigon's 522 ms, so Besu has the larger engine-API bill.</p>
<p>But the bill is not the deadline. Prysm publishes <code>chain_service_processing_milliseconds</code>, its own total block-processing time, at the same one observation per block:</p>
<table><thead><tr><th>Execution client</th><th>Block processing, mean</th><th>Above its own <code>newPayload</code></th></tr></thead><tbody><tr><td><strong>Ethrex</strong></td><td>265 ms</td><td>+94 ms</td></tr><tr><td><strong>Geth</strong></td><td>415 ms</td><td>+89 ms</td></tr><tr><td><strong>Nethermind</strong></td><td>445 ms</td><td>+72 ms</td></tr><tr><td><strong>Besu</strong></td><td>512 ms</td><td>+70 ms</td></tr><tr><td><strong>Erigon</strong></td><td>573 ms</td><td>+57 ms</td></tr></tbody></table>
<p>Every client sits 57 to 94 ms above its own <code>newPayload</code> mean, Besu included at +70 ms. The 208 ms head-update call is therefore measurably outside the region Prysm spends importing a block, which is both why it costs no attestation budget and why it does not make Besu the worst client for duty timing. On the quantity that governs when a block becomes attestable, the order does not reorder at all: Erigon is still last. Besu has the largest engine-API bill and the fourth-longest wait to attestability, and both statements are worth knowing.</p>
<p>One caveat on the off-path finding: our fleet does not propose blocks. A proposing node calls <code>forkchoiceUpdated</code> with payload attributes to start block assembly, and there a slow head update would sit on a path that matters.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="arrival-execution-client-independent-for-the-third-time">Arrival, execution-client-independent for the third time<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-prysm#arrival-execution-client-independent-for-the-third-time" class="hash-link" aria-label="Direct link to Arrival, execution-client-independent for the third time" title="Direct link to Arrival, execution-client-independent for the third time" translate="no">​</a></h2>
<table><thead><tr><th>Execution client</th><th>Mean block arrival</th></tr></thead><tbody><tr><td>Geth</td><td>1,833 ms</td></tr><tr><td>Besu</td><td>1,836 ms</td></tr><tr><td>Nethermind</td><td>1,840 ms</td></tr><tr><td>Ethrex</td><td>1,844 ms</td></tr><tr><td>Erigon</td><td>1,850 ms</td></tr></tbody></table>
<p>Seventeen milliseconds separate fastest from slowest, on clients whose <code>newPayload</code> latencies span 345 ms. Arrival happens before the execution client is asked for anything, so it cannot carry the execution client's signature, and across three editions it never has. If your blocks arrive late, that is peering and proposers, and our <a class="" href="https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis">peering deep dive</a> is where to take it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-to-measure-on-your-own-nodes">What to measure on your own nodes<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-prysm#what-to-measure-on-your-own-nodes" class="hash-link" aria-label="Direct link to What to measure on your own nodes" title="Direct link to What to measure on your own nodes" translate="no">​</a></h2>
<ul>
<li class=""><strong>Watch both engine calls.</strong> Whichever client you run, it publishes both: <code>new_payload_v1_latency_milliseconds</code> and <code>forkchoice_updated_v1_latency_milliseconds</code> on Prysm, <code>execution_layer_request_times{method=...}</code> on Lighthouse, <code>engine_api_request_duration_seconds{request=...}</code> on Nimbus. Watching only <code>newPayload</code> hides a call that on one client here costs 200 ms.</li>
<li class=""><strong>Watch the tail, not the mean.</strong> Every client in this comparison is comfortable on an average block and into the seconds at the 99th percentile.</li>
<li class=""><strong>Compare execution clients under one consensus client, or not at all.</strong> A 160 ms spread at fixed version across our own pairings is the reason we will not rank the middle of the field. If you are choosing between two clients whose published numbers are within 10 or 15%, ask what consensus client produced them, and rerun the comparison on your own stack before acting on it.</li>
<li class=""><strong>Separate the bill from the deadline.</strong> Engine-API wall time and time-to-attestable are different quantities that rank clients differently. Pair the engine histograms with your client's block-processing metric, and with attestation inclusion distance from rated.network or beaconcha.in as the outcome.</li>
<li class=""><strong>Do not read <code>attestation_inclusion_delay_slots</code> as your own duty performance.</strong> It came out identical across all five pairings because it describes the network, not this node.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="coming-next-in-the-series">Coming next in the series<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-prysm#coming-next-in-the-series" class="hash-link" aria-label="Direct link to Coming next in the series" title="Direct link to Coming next in the series" translate="no">​</a></h2>
<p>Three consensus clients down, and the useful surprise is that they overlap more than we assumed: all three time the engine API completely, which turns the series from a tour of instruments into a way to cross-check results. Teku, Lodestar and Grandine are next, and all three already appear as drivers in the table above. What we will be asking of them is not only what they instrument, but which of our findings survive being measured somewhere else.</p>
<p>Then the finale, which is the one we are now looking forward to: six consensus clients, six execution clients, every instrument against every other, and an honest accounting of which claims from the earlier editions of this series hold up under that comparison and which do not. This edition already found two that need revisiting. We would rather publish that list than quietly not mention it.</p>
<p>Holding hardware and consensus client fixed while varying the execution client is the cut that makes execution cost legible, and cross-checking the same question against a second and third instrument is what tells you which parts of it were about the client at all. That work, including catching a node that only looks synced and catching our own overreach, is what StereumLabs AI does on our fleet, on <a class="" href="https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack">the measurement stack we described here</a>. The same data supports doing it yourself on matched versions and identical hardware. If you run Ethereum infrastructure and want this lens on your own nodes, reach us at <a href="https://stereumlabs.com/" target="_blank" rel="noopener noreferrer" class="">stereumlabs.com</a> or <a href="mailto:contact@stereumlabs.com" target="_blank" rel="noopener noreferrer" class="">contact@stereumlabs.com</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="methodology">Methodology<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-prysm#methodology" class="hash-link" aria-label="Direct link to Methodology" title="Direct link to Methodology" translate="no">​</a></h2>
<p>Numbers come from the three consensus clients' engine-API and block-timing histograms on our NDC2 deployment (Vienna), queried on the <code>Prometheus-cold</code> datasource (uid <code>aez9ck4wz05q8e</code>), with the fleet labels documented in <a class="" href="https://docs.stereumlabs.com/docs/dashboards/build-your-own">build your own dashboards</a>. The window is the three days from 2026-07-24T00:00:00Z to 2026-07-27T00:00:00Z, with <code>increase(...[3d])</code> evaluated at the closing anchor so figures are stable and reproducible rather than drifting with query time. The window sits inside a period when no execution-client version changed on these pairings; the last bump was on 2026-07-22.</p>
<ul>
<li class=""><strong>Prysm's metrics.</strong> <code>new_payload_v1_latency_milliseconds</code> and <code>forkchoice_updated_v1_latency_milliseconds</code>, histograms in milliseconds with finite buckets at 25, 50, 100, 200, 500, 1000, 2000 and 4000 ms; <code>block_arrival_latency_milliseconds</code> with finite buckets at 100 to 24000 ms; <code>chain_service_processing_milliseconds</code> as a summary. Values are for <code>cc_client="prysm-super", cc_version="v7.1.7", deployment="NDC2"</code> grouped by <code>ec_client</code>. Means are <code>increase(_sum[3d]) / increase(_count[3d])</code>, which is exact. Percentiles are <code>histogram_quantile</code> over windowed buckets and are bucket-interpolated; the 99th percentiles land in the 2000-to-4000 ms band and are approximate.</li>
<li class=""><strong>The three-instrument comparison</strong> uses <code>execution_layer_request_times{method="new_payload"}</code> on <code>cc_client="lighthouse-super"</code> (v8.2.1), <code>engine_api_request_duration_seconds{request="newPayload"}</code> on <code>cc_client="nimbus-super"</code> (v26.7.0), and Prysm's <code>new_payload_v1_latency_milliseconds</code>, all in the same window for the same execution-client versions. The Lighthouse and Nimbus metrics are in seconds and converted. Coverage is comparable: <code>increase(_count[3d])</code> gives about 21,571 (Lighthouse), 21,577 (Nimbus) and 21,565 (Prysm) per pairing against 21,600 slots. The same three metrics with the <code>forkchoice_updated</code>, <code>forkchoiceUpdated</code> and <code>forkchoice_updated_v1</code> selectors give the second table, at about 22,266, 21,577 and 21,562 calls respectively.</li>
<li class=""><strong>The definitional effect</strong> is measured within Lighthouse on one host: <code>avg_over_time(beacon_block_delay_execution_time[3d])</code> against the mean of <code>execution_layer_request_times{method="new_payload"}</code>, giving Besu 390 to 403 ms, Geth 289 to 311, Nethermind 241 to 275, Ethrex 97 to 139 and Erigon 427 to 503. No consensus client can observe an execution client's internal work, since the engine API returns no timing, so both of these are consensus-side wall clocks that differ in how much of the call they bracket. An earlier draft of this post described the Lighthouse gauge as an internal execution timer and attributed the Geth-Nethermind ordering difference to that distinction. Both were wrong, and the two paragraphs below are why.</li>
<li class=""><strong>Pairing variance</strong> is measured with the execution clients' own timers, which no consensus client is in the loop for. <code>avg_over_time(nethermind_new_payload_execution_time[3d])</code> for <code>ec_version="1.39.2"</code> across the six pairings gives 195, 239, 263, 311, 341 and 355 ms, for the Grandine, Teku, Lighthouse, Nimbus, Lodestar and Prysm pairings respectively, on 4,320 samples each. The Lighthouse-to-Prysm difference of 92 ms is the dominant term in what an earlier draft of this post read as a measurement-definition effect.</li>
<li class=""><strong>Ruling out the machine.</strong> Over the same window, on the same six execution-client hosts, <code>node_cpu_seconds_total</code> gives 5.2 to 6.7% busy, <code>node_disk_io_time_seconds_total</code> gives 5.1 to 7.3% utilisation, <code>node_disk_read_bytes_total</code> gives 1.83 to 2.13 MB/s, <code>node_memory_Cached_bytes</code> gives 8.9 to 9.9 GiB, and used filesystem bytes span 1.1506 to 1.1516 TiB, a 0.1% difference. All six are identical 12-core bare metal in one rack with sub-millisecond ping. Neither CPU nor disk was near saturation on any host, the load ordering does not match the latency ordering, and the database sizes are equal, so we attribute the spread to the pairing rather than to the hardware and leave the mechanism open.</li>
<li class=""><strong>On resolvability.</strong> Within a single instrument the differences we report are resolvable: Lighthouse's gauge holds 4,320 samples per pairing over the window with standard deviations near 494 ms (Geth) and 352 ms (Nethermind), and Prysm's histogram is a complete per-slot census. Those samples are 60 seconds apart and serially correlated, so a naive independent-samples standard error understates the uncertainty. We do not rest anything on it: the cross-instrument comparisons in this post are limited by between-pairing variance of 92 to 160 ms, which is larger than the effects a significance test would be resolving, so we report the extremes and the reproducible Besu result and decline the middle.</li>
<li class=""><strong>Besu's <code>forkchoiceUpdated</code> distribution</strong> under Prysm, from the raw buckets: about 14% of calls under 100 ms, 58% under 200 ms, 97.6% under 500 ms and 0.5% over 1 s, with an interpolated median near 183 ms. The four other clients' p90 values of 22.8 to 23.2 ms are first-bucket interpolation artifacts, since 97 to 99% of their calls land under the 25 ms bucket edge, and should not be read as those clients agreeing with each other.</li>
<li class=""><strong>The engine-API bill against the deadline.</strong> <code>chain_service_processing_milliseconds</code> on Prysm, one observation per block like the two engine histograms, gives Ethrex 265, Geth 415, Nethermind 445, Besu 512 and Erigon 573 ms, so each client sits 57 to 94 ms above its own <code>newPayload</code> mean and the 208 ms <code>forkchoiceUpdated</code> is outside that region. Summing the two engine means is valid as an expected per-slot total because both denominators are the same, but it covers only the two calls these clients time per block, not all engine traffic. Our fleet does not propose blocks, so the payload-attribute variant of <code>forkchoiceUpdated</code> is not exercised here.</li>
<li class=""><strong><code>attestation_inclusion_delay_slots</code></strong> returned 3.586 slots for all five synced pairings, identical to three decimals, the signature of a network-wide quantity rather than a per-node one. Our fleet runs no live validators, so no metric here depends on attestation signing.</li>
<li class=""><strong>Sync was verified from logs, not metrics.</strong> At both ends of the window each execution client's own container log showed it at the chain tip: Geth's <code>Chain head was updated number 25,598,917</code> and <code>25,620,466</code>, Erigon's <code>head updated</code>, Besu's block-add lines, Nethermind's <code>Received ForkChoice: 25598917</code>, and Ethrex's <code>Prewarm pass for block 25598918</code>. Reth is excluded on three independent grounds: zero <code>VALID</code> payload responses against 40,556 optimistic ones on this pairing, <code>reth_sync_checkpoint{stage="Execution"}</code> at 16,340,084 against a chain past 25.6M, and no <code>Canonical chain committed</code> line in the three-day window. Its <code>Received new payload</code> lines do reach tip block numbers, which is the trap: receiving a payload is not importing it. On identical 12-core hosts; consensus and validator processes run on separate machines.</li>
</ul>]]></content:encoded>
            <category>client comparison</category>
            <category>validator duties</category>
            <category>observability</category>
            <category>engine API</category>
            <category>Prysm</category>
            <category>Lighthouse</category>
            <category>Nimbus</category>
            <category>Geth</category>
            <category>Nethermind</category>
            <category>Besu</category>
            <category>Erigon</category>
            <category>Ethrex</category>
            <category>StereumLabs AI</category>
        </item>
        <item>
            <title><![CDATA[Where the slot goes: Nimbus and the execution timing it can't see]]></title>
            <link>https://docs.stereumlabs.com/blog/where-the-slot-goes-nimbus</link>
            <guid>https://docs.stereumlabs.com/blog/where-the-slot-goes-nimbus</guid>
            <pubDate>Wed, 01 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Nimbus exposes a complete block-arrival histogram but no execution timing, so its own metrics cannot rank execution clients the way Lighthouse can.]]></description>
            <content:encoded><![CDATA[<p>In <a class="" href="https://docs.stereumlabs.com/blog/where-the-slot-goes-lighthouse">the first edition of this series</a> we measured, under Lighthouse, where a 12-second slot goes against the 4-second attestation deadline, and found that the execution client you pick is the lever: it shifts how often a node lands late enough to fail attestations by about 1.5x across the mainstream clients, and 3.7x once Erigon's disk-bound tail is counted. This edition runs the same six execution clients on the same bare-metal fleet, and asks the same question of Nimbus. The answer is the finding: Nimbus cannot tell you which execution client is costing you, because the one timing it reports is block arrival, and arrival is the part the execution client does not touch.</p>
<p>That is not a gap in our data. It is what Nimbus exposes. Where Lighthouse breaks the path to attestable into arrival, consensus verification and execution verification, Nimbus publishes a single histogram of block-arrival delay. The good news is that this histogram is complete, counting every block, not the once-a-minute sample Lighthouse's gauges gave us. The catch is that it sees only the network-and-proposer part of the slot, so the 3.7x spread that mattered under Lighthouse is simply not in the data Nimbus reports.</p>
<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>Read this first</div><div class="admonitionContent_BuS1"><ul>
<li class=""><strong>Nimbus reports arrival, not execution.</strong> Its <code>beacon_block_delay</code> histogram measures the time from slot start to block arrival. It does not expose the execution-verification slice, a per-component breakdown, or a would-fail-attestations counter. Those are Lighthouse metrics, and they are empty for Nimbus on our fleet. So the per-client numbers below are arrival timing, which is set by the network and the proposer, not by your execution client.</li>
<li class=""><strong>The arrival distribution is complete, not sampled.</strong> Unlike Lighthouse's block-delay gauges, which were read about once a minute, this histogram counts every block Nimbus times, so the mean and the count past 4 seconds are exact, not a once-a-minute estimate. The buckets are coarse (2 s wide), so the median and 99th percentile are interpolated: read the 99th percentile as "just under 4 s," not a precise figure. The count past the 4 s bucket boundary is the trustworthy tail number.</li>
<li class=""><strong>Reth is excluded.</strong> It was still back-filling throughout this window (v2.3.0), its sync log reporting <code>Executing stage 4/14</code> after six days on this deployment while the tip was past 25.4M, so it was not a synced node and its arrival timing is not comparable. See <a class="" href="https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026">the sync-speed census</a> for why a node can look alive on metrics while a log check shows it is still syncing.</li>
<li class=""><strong>Window and versions.</strong> Three days, 2026-06-27 to 2026-06-30, on the current Nimbus deployment <code>multiarch-v26.6.0</code> paired with Geth v1.17.3, Nethermind 1.38.1, Besu 26.6.1, Erigon v3.4.4, Ethrex 17.0.0, on the NDC2 bare-metal hosts in Vienna. For Besu, Erigon and Ethrex these are a step newer than the Lighthouse edition's window (the methodology lists both). Each execution client's sync state was confirmed at the tip from its own container logs across the window, not from metrics alone.</li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="two-instruments-two-views-of-the-same-slot">Two instruments, two views of the same slot<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-nimbus#two-instruments-two-views-of-the-same-slot" class="hash-link" aria-label="Direct link to Two instruments, two views of the same slot" title="Direct link to Two instruments, two views of the same slot" translate="no">​</a></h2>
<p>The slot is the same one Lighthouse showed us: a block is proposed elsewhere, gossiped across the network, observed locally somewhere around 2 seconds in, then verified by the consensus and execution layers before it can be attested to, all against the 4-second line. What changes between consensus clients is which parts of that path they put a number on.</p>
<p><img decoding="async" loading="lazy" alt="Two instruments for the same slot: Lighthouse breaks the path into block arrival, consensus verification and execution verification with a separate would-fail counter, while Nimbus publishes a single histogram covering block arrival only" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDQ3MCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPGRlZnM+CiAgICA8cGF0dGVybiBpZD0iaGF0Y2giIHdpZHRoPSI4IiBoZWlnaHQ9IjgiIHBhdHRlcm5Vbml0cz0idXNlclNwYWNlT25Vc2UiIHBhdHRlcm5UcmFuc2Zvcm09InJvdGF0ZSg0NSkiPgogICAgICA8bGluZSB4MT0iMCIgeTE9IjAiIHgyPSIwIiB5Mj0iOCIgc3Ryb2tlPSIjNTQ2MDdkIiBzdHJva2Utd2lkdGg9IjIiLz4KICAgIDwvcGF0dGVybj4KICA8L2RlZnM+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNDcwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTQiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjciIGZvbnQtd2VpZ2h0PSI3MDAiPlR3byBpbnN0cnVtZW50cywgb25lIHNsb3Q8L3RleHQ+CiAgPHRleHQgeD0iNDgiIHk9Ijg0IiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE2Ij53aGF0IGVhY2ggY29uc2Vuc3VzIGNsaWVudCBwdXRzIGEgbnVtYmVyIG9uLCBhZ2FpbnN0IHRoZSA0LXNlY29uZCBhdHRlc3RhdGlvbiBkZWFkbGluZTwvdGV4dD4KCiAgPCEtLSBsZWdlbmQgLS0+CiAgPHJlY3QgeD0iNjkwIiB5PSI0MCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiByeD0iMyIgZmlsbD0iIzU0NjA3ZCIvPjx0ZXh0IHg9IjcxMiIgeT0iNTMiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTQiPmFycml2YWw8L3RleHQ+CiAgPHJlY3QgeD0iODAwIiB5PSI0MCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPjx0ZXh0IHg9IjgyMiIgeT0iNTMiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTQiPmNvbnNlbnN1czwvdGV4dD4KICA8cmVjdCB4PSI5MzAiIHk9IjQwIiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHJ4PSIzIiBmaWxsPSIjZjk3MzE2Ii8+PHRleHQgeD0iOTUyIiB5PSI1MyIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCI+ZXhlY3V0aW9uPC90ZXh0PgoKICA8IS0tIHRpbWUgYXhpcyB4MD0yNjAgcz0xOTAgcHgvcyAtLT4KICA8ZyBzdHJva2U9IiMxYzI2NTQiIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8bGluZSB4MT0iNDUwIiB5MT0iMTE4IiB4Mj0iNDUwIiB5Mj0iMzUwIi8+CiAgICA8bGluZSB4MT0iNjQwIiB5MT0iMTE4IiB4Mj0iNjQwIiB5Mj0iMzUwIi8+CiAgICA8bGluZSB4MT0iODMwIiB5MT0iMTE4IiB4Mj0iODMwIiB5Mj0iMzUwIi8+CiAgPC9nPgogIDxsaW5lIHgxPSIxMDIwIiB5MT0iMTE4IiB4Mj0iMTAyMCIgeTI9IjM1MCIgc3Ryb2tlPSIjZjg3MTcxIiBzdHJva2Utd2lkdGg9IjIuNSIgc3Ryb2tlLWRhc2hhcnJheT0iNyA1Ii8+CiAgPHRleHQgeD0iMTAyMCIgeT0iMTExIiBmaWxsPSIjZmNhNWE1IiBmb250LXNpemU9IjE1IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5hdHRlc3RhdGlvbiBkZWFkbGluZSDCtyA0IHM8L3RleHQ+CiAgPGcgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+CiAgICA8dGV4dCB4PSIyNjAiIHk9IjM3MiI+MDwvdGV4dD48dGV4dCB4PSI0NTAiIHk9IjM3MiI+MSBzPC90ZXh0Pjx0ZXh0IHg9IjY0MCIgeT0iMzcyIj4yIHM8L3RleHQ+PHRleHQgeD0iODMwIiB5PSIzNzIiPjMgczwvdGV4dD48dGV4dCB4PSIxMDIwIiB5PSIzNzIiPjQgczwvdGV4dD4KICA8L2c+CgogIDwhLS0gUm93IDE6IExpZ2h0aG91c2UgLS0+CiAgPHRleHQgeD0iMjQwIiB5PSIxNTUiIGZpbGw9IiNlMmU4ZjQiIGZvbnQtc2l6ZT0iMTYiIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI2MDAiPkxpZ2h0aG91c2U8L3RleHQ+CiAgPHJlY3QgeD0iMjYwIiB5PSIxNTAiIHdpZHRoPSIzNDIiIGhlaWdodD0iNDAiIHJ4PSIzIiBmaWxsPSIjNTQ2MDdkIi8+CiAgPHJlY3QgeD0iNjAyIiB5PSIxNTAiIHdpZHRoPSIzMi4zIiBoZWlnaHQ9IjQwIiBmaWxsPSIjNzk4YmZmIi8+CiAgPHJlY3QgeD0iNjM0LjMiIHk9IjE1MCIgd2lkdGg9IjU3IiBoZWlnaHQ9IjQwIiByeD0iMyIgZmlsbD0iI2Y5NzMxNiIvPgogIDxsaW5lIHgxPSI2OTEuMyIgeTE9IjE0NCIgeDI9IjY5MS4zIiB5Mj0iMTk2IiBzdHJva2U9IiNmZGU2OGEiIHN0cm9rZS13aWR0aD0iMi41Ii8+CiAgPHRleHQgeD0iNzAwIiB5PSIxNzYiIGZpbGw9IiNmZGU2OGEiIGZvbnQtc2l6ZT0iMTMiPmF0dGVzdGFibGU8L3RleHQ+CiAgPHRleHQgeD0iNDMxIiB5PSIxNzUiIGZpbGw9IiNlMmU4ZjQiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZvbnQtd2VpZ2h0PSI2MDAiPmJsb2NrIGFycml2YWw8L3RleHQ+CiAgPHRleHQgeD0iMjYwIiB5PSIyMjIiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTMiPmZvdXIgZ2F1Z2VzOiBhcnJpdmFsIMK3IGNvbnNlbnN1cyDCtyBleGVjdXRpb24gwrcgYXR0ZXN0YWJsZSwgcGx1cyBhIHdvdWxkLWZhaWwgY291bnRlciwgc2FtcGxlZCBhYm91dCBvbmNlIGEgbWludXRlPC90ZXh0PgoKICA8IS0tIFJvdyAyOiBOaW1idXMgLS0+CiAgPHRleHQgeD0iMjQwIiB5PSIyOTUiIGZpbGw9IiNlMmU4ZjQiIGZvbnQtc2l6ZT0iMTYiIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI2MDAiPk5pbWJ1czwvdGV4dD4KICA8cmVjdCB4PSIyNjAiIHk9IjI5MCIgd2lkdGg9IjM0MiIgaGVpZ2h0PSI0MCIgcng9IjMiIGZpbGw9IiM1NDYwN2QiLz4KICA8cG9seWxpbmUgcG9pbnRzPSIyNzAsMzI2IDI5MCwzMTggMzEwLDMwNiAzMzAsMzAwIDM1MCwzMDggMzcwLDMxNiAzOTAsMzIyIDQxMCwzMjYgNDMwLDMyOCA0NTAsMzMwIDQ4MCwzMzEgNTIwLDMzMSA1NjAsMzMxIDYwMCwzMzEiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2FlYjlkYSIgc3Ryb2tlLXdpZHRoPSIxLjUiIG9wYWNpdHk9IjAuNyIvPgogIDx0ZXh0IHg9IjQzMSIgeT0iMzE1IiBmaWxsPSIjZTJlOGY0IiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmb250LXdlaWdodD0iNjAwIj5ibG9jayBhcnJpdmFsIMK3IHRydWUgaGlzdG9ncmFtPC90ZXh0PgogIDxyZWN0IHg9IjYwMiIgeT0iMjkwIiB3aWR0aD0iODkuMyIgaGVpZ2h0PSI0MCIgcng9IjMiIGZpbGw9InVybCgjaGF0Y2gpIiBzdHJva2U9IiM1NDYwN2QiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtZGFzaGFycmF5PSI1IDQiLz4KICA8dGV4dCB4PSI2NDYiIHk9IjMxNiIgZmlsbD0iIzhlOWJiZCIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+ZXhlY3V0aW9uPC90ZXh0PgogIDx0ZXh0IHg9IjcwMCIgeT0iMzE1IiBmaWxsPSIjOGU5YmJkIiBmb250LXNpemU9IjEzIj5ub3QgZXhwb3NlZDwvdGV4dD4KICA8dGV4dCB4PSIyNjAiIHk9IjM2MiIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMyI+b25lIGhpc3RvZ3JhbTogYmxvY2sgYXJyaXZhbCBvbmx5LCBjb21wbGV0ZSB0byB0aGUgYmxvY2ssIG5vIGV4ZWN1dGlvbiBzbGljZSwgbm8gd291bGQtZmFpbCBjb3VudGVyPC90ZXh0PgoKICA8dGV4dCB4PSI0OCIgeT0iNDMwIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE1Ij5MaWdodGhvdXNlIHRpbWVzIHRoZSBleGVjdXRpb24gc2xpY2UgYnV0IG9ubHkgc2FtcGxlcyBpdC4gTmltYnVzIG1lYXN1cmVzIGFycml2YWwgaW4gZnVsbCwgYW5kIHN0b3BzIHRoZXJlLjwvdGV4dD4KICA8dGV4dCB4PSI0OCIgeT0iNDUyIiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEzIj5OZWl0aGVyIGlzIHRoZSB3aG9sZSBzbG90LiBUaGUgY29uc2Vuc3VzIGNsaWVudCB5b3UgcnVuIGRlY2lkZXMgd2hpY2ggaGFsZiB5b3UgZ2V0LjwvdGV4dD4KICA8dGV4dCB4PSIxMTUyIiB5PSI0NTIiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTMiIHRleHQtYW5jaG9yPSJlbmQiPmRvY3Muc3RlcmV1bWxhYnMuY29tPC90ZXh0Pgo8L3N2Zz4K" width="1200" height="470" class="img_ev3q"></p>
<p>Lighthouse gives the granular gauges (<code>beacon_block_delay_observed_slot_start</code>, <code>_consensus_verification_time</code>, <code>_execution_time</code>, <code>_attestable_slot_start</code>) plus the <code>head_slot_start_exceeded</code> counter, sampled about once a minute. Nimbus gives one histogram, <code>beacon_block_delay</code>, of arrival delay, complete to the block. Neither is the full picture. Lighthouse shows you the execution slice but only in samples; Nimbus shows you arrival in full but stops there. The consensus client you run decides which half of the trade you get.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-nimbus-shows-well-the-arrival-distribution">What Nimbus shows well: the arrival distribution<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-nimbus#what-nimbus-shows-well-the-arrival-distribution" class="hash-link" aria-label="Direct link to What Nimbus shows well: the arrival distribution" title="Direct link to What Nimbus shows well: the arrival distribution" translate="no">​</a></h2>
<p>For the part it does measure, Nimbus measures it completely. Where Lighthouse sampled its block-delay gauges about once a minute, Nimbus's histogram counts every block it times, so the mean and the count past 4 seconds are exact rather than the conservative floors that sampling forced on us in the first edition. Over the window, per pairing:</p>
<p><img decoding="async" loading="lazy" alt="Block-arrival timing under Nimbus, per execution client: mean arrival around 2 seconds, 90th percentile around 3.5 seconds, and a few tenths of a percent of blocks arriving after the 4-second deadline, with the five clients in a narrow band" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDQ4MCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNDgwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTQiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjciIGZvbnQtd2VpZ2h0PSI3MDAiPkJsb2NrIGFycml2YWwgdW5kZXIgTmltYnVzLCBwZXIgZXhlY3V0aW9uIGNsaWVudDwvdGV4dD4KICA8dGV4dCB4PSI0OCIgeT0iODQiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTYiPm1lYW4gYXJyaXZhbCAoYmFyKSBhbmQgOTB0aCBwZXJjZW50aWxlICh0aWNrKSDCtyBmaXZlIHN5bmNlZCBjbGllbnRzLCBpZGVudGljYWwgaGFyZHdhcmUgwrcgYXR0ZXN0YXRpb24gZHVlIGF0IDQgczwvdGV4dD4KCiAgPCEtLSBsZWdlbmQgLS0+CiAgPHJlY3QgeD0iNzIwIiB5PSI0MCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPjx0ZXh0IHg9Ijc0MiIgeT0iNTMiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTQiPm1lYW4gYXJyaXZhbDwvdGV4dD4KICA8bGluZSB4MT0iODU4IiB5MT0iNDAiIHgyPSI4NTgiIHkyPSI1NiIgc3Ryb2tlPSIjZmRlNjhhIiBzdHJva2Utd2lkdGg9IjMiLz48dGV4dCB4PSI4NjgiIHk9IjUzIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0Ij45MHRoIHBlcmNlbnRpbGU8L3RleHQ+CgogIDwhLS0gbWVhbiBjbHVzdGVyIGJhbmQgeCA2NTcuLjY3OCAtLT4KICA8cmVjdCB4PSI2NTciIHk9IjEzMiIgd2lkdGg9IjIxIiBoZWlnaHQ9IjI3OCIgZmlsbD0iIzUwNDZlNSIgb3BhY2l0eT0iMC4xNiIvPgogIDx0ZXh0IHg9IjY2OCIgeT0iMTI2IiBmaWxsPSIjYWViOWRhIiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5hbGwgZml2ZSB3aXRoaW4gfjAuMSBzPC90ZXh0PgoKICA8IS0tIGF4aXMgeDA9MzAwIHM9MTg0LjQgcHgvcyAtLT4KICA8ZyBzdHJva2U9IiMxYzI2NTQiIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8bGluZSB4MT0iNDg0LjQiIHkxPSIxMzIiIHgyPSI0ODQuNCIgeTI9IjQxMiIvPgogICAgPGxpbmUgeDE9IjY2OC45IiB5MT0iMTMyIiB4Mj0iNjY4LjkiIHkyPSI0MTIiLz4KICAgIDxsaW5lIHgxPSI4NTMuMyIgeTE9IjEzMiIgeDI9Ijg1My4zIiB5Mj0iNDEyIi8+CiAgPC9nPgogIDxsaW5lIHgxPSIxMDM3LjgiIHkxPSIxMzIiIHgyPSIxMDM3LjgiIHkyPSI0MTIiIHN0cm9rZT0iI2Y4NzE3MSIgc3Ryb2tlLXdpZHRoPSIyLjUiIHN0cm9rZS1kYXNoYXJyYXk9IjcgNSIvPgogIDx0ZXh0IHg9IjEwMzcuOCIgeT0iMTI1IiBmaWxsPSIjZmNhNWE1IiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5kZWFkbGluZSDCtyA0IHM8L3RleHQ+CiAgPGcgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+CiAgICA8dGV4dCB4PSIzMDAiIHk9IjQzNCI+MDwvdGV4dD48dGV4dCB4PSI0ODQuNCIgeT0iNDM0Ij4xIHM8L3RleHQ+PHRleHQgeD0iNjY4LjkiIHk9IjQzNCI+MiBzPC90ZXh0Pjx0ZXh0IHg9Ijg1My4zIiB5PSI0MzQiPjMgczwvdGV4dD48dGV4dCB4PSIxMDM3LjgiIHk9IjQzNCI+NCBzPC90ZXh0PgogIDwvZz4KICA8dGV4dCB4PSIxMTUwIiB5PSIxMTAiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTMiIHRleHQtYW5jaG9yPSJlbmQiPnBhc3QgNCBzIMK3IDMgZGF5czwvdGV4dD4KCiAgPCEtLSBCZXN1IG1lYW4gMS45NCAoNjU3LjcpIHA5MCAzLjQzICg5MzIuNSkgLS0+CiAgPHRleHQgeD0iMjg4IiB5PSIxNjciIGZpbGw9IiNlMmU4ZjQiIGZvbnQtc2l6ZT0iMTYiIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI2MDAiPkJlc3U8L3RleHQ+CiAgPHJlY3QgeD0iMzAwIiB5PSIxNTAiIHdpZHRoPSIzNTcuNyIgaGVpZ2h0PSIyNiIgcng9IjMiIGZpbGw9IiM3OThiZmYiLz4KICA8dGV4dCB4PSI2NDkiIHk9IjE2OCIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9ImVuZCI+MS45NCBzPC90ZXh0PgogIDxsaW5lIHgxPSI5MzIuNSIgeTE9IjE0NiIgeDI9IjkzMi41IiB5Mj0iMTgwIiBzdHJva2U9IiNmZGU2OGEiIHN0cm9rZS13aWR0aD0iMyIvPgogIDx0ZXh0IHg9IjkzMi41IiB5PSIxOTYiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTIiIHRleHQtYW5jaG9yPSJtaWRkbGUiPjMuNDM8L3RleHQ+CiAgPHRleHQgeD0iMTE1MCIgeT0iMTY4IiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0iZW5kIj4zNzwvdGV4dD4KCiAgPCEtLSBFcmlnb24gbWVhbiAxLjk3ICg2NjMuMykgcDkwIDMuNDUgKDkzNi4yKSAtLT4KICA8dGV4dCB4PSIyODgiIHk9IjIyMiIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxNiIgdGV4dC1hbmNob3I9ImVuZCIgZm9udC13ZWlnaHQ9IjYwMCI+RXJpZ29uPC90ZXh0PgogIDxyZWN0IHg9IjMwMCIgeT0iMjA1IiB3aWR0aD0iMzYzLjMiIGhlaWdodD0iMjYiIHJ4PSIzIiBmaWxsPSIjNzk4YmZmIi8+CiAgPHRleHQgeD0iNjU1IiB5PSIyMjMiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJlbmQiPjEuOTcgczwvdGV4dD4KICA8bGluZSB4MT0iOTM2LjIiIHkxPSIyMDEiIHgyPSI5MzYuMiIgeTI9IjIzNSIgc3Ryb2tlPSIjZmRlNjhhIiBzdHJva2Utd2lkdGg9IjMiLz4KICA8dGV4dCB4PSI5MzYuMiIgeT0iMjUxIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjEyIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj4zLjQ1PC90ZXh0PgogIDx0ZXh0IHg9IjExNTAiIHk9IjIyMyIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9ImVuZCI+NDA8L3RleHQ+CgogIDwhLS0gRXRocmV4IG1lYW4gMi4wMiAoNjcyLjUpIHA5MCAzLjUwICg5NDUuNCkgLS0+CiAgPHRleHQgeD0iMjg4IiB5PSIyNzciIGZpbGw9IiNlMmU4ZjQiIGZvbnQtc2l6ZT0iMTYiIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI2MDAiPkV0aHJleDwvdGV4dD4KICA8cmVjdCB4PSIzMDAiIHk9IjI2MCIgd2lkdGg9IjM3Mi41IiBoZWlnaHQ9IjI2IiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPgogIDx0ZXh0IHg9IjY2NCIgeT0iMjc4IiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0iZW5kIj4yLjAyIHM8L3RleHQ+CiAgPGxpbmUgeDE9Ijk0NS40IiB5MT0iMjU2IiB4Mj0iOTQ1LjQiIHkyPSIyOTAiIHN0cm9rZT0iI2ZkZTY4YSIgc3Ryb2tlLXdpZHRoPSIzIi8+CiAgPHRleHQgeD0iOTQ1LjQiIHk9IjMwNiIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+My41MDwvdGV4dD4KICA8dGV4dCB4PSIxMTUwIiB5PSIyNzgiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJlbmQiPjgwPC90ZXh0PgoKICA8IS0tIEdldGggbWVhbiAyLjA1ICg2NzguMCkgcDkwIDMuNTQgKDk1Mi44KSAtLT4KICA8dGV4dCB4PSIyODgiIHk9IjMzMiIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxNiIgdGV4dC1hbmNob3I9ImVuZCIgZm9udC13ZWlnaHQ9IjYwMCI+R2V0aDwvdGV4dD4KICA8cmVjdCB4PSIzMDAiIHk9IjMxNSIgd2lkdGg9IjM3OC4wIiBoZWlnaHQ9IjI2IiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPgogIDx0ZXh0IHg9IjY3MCIgeT0iMzMzIiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0iZW5kIj4yLjA1IHM8L3RleHQ+CiAgPGxpbmUgeDE9Ijk1Mi44IiB5MT0iMzExIiB4Mj0iOTUyLjgiIHkyPSIzNDUiIHN0cm9rZT0iI2ZkZTY4YSIgc3Ryb2tlLXdpZHRoPSIzIi8+CiAgPHRleHQgeD0iOTUyLjgiIHk9IjM2MSIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+My41NDwvdGV4dD4KICA8dGV4dCB4PSIxMTUwIiB5PSIzMzMiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJlbmQiPjg2PC90ZXh0PgoKICA8IS0tIE5ldGhlcm1pbmQgbWVhbiAyLjA1ICg2NzguMCkgcDkwIDMuNTQgKDk1Mi44KSAtLT4KICA8dGV4dCB4PSIyODgiIHk9IjM4NyIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxNiIgdGV4dC1hbmNob3I9ImVuZCIgZm9udC13ZWlnaHQ9IjYwMCI+TmV0aGVybWluZDwvdGV4dD4KICA8cmVjdCB4PSIzMDAiIHk9IjM3MCIgd2lkdGg9IjM3OC4wIiBoZWlnaHQ9IjI2IiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPgogIDx0ZXh0IHg9IjY3MCIgeT0iMzg4IiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0iZW5kIj4yLjA1IHM8L3RleHQ+CiAgPGxpbmUgeDE9Ijk1Mi44IiB5MT0iMzY2IiB4Mj0iOTUyLjgiIHkyPSI0MDAiIHN0cm9rZT0iI2ZkZTY4YSIgc3Ryb2tlLXdpZHRoPSIzIi8+CiAgPHRleHQgeD0iOTUyLjgiIHk9IjQxNiIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+My41NDwvdGV4dD4KICA8dGV4dCB4PSIxMTUwIiB5PSIzODgiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJlbmQiPjEwMTwvdGV4dD4KCiAgPHRleHQgeD0iNDgiIHk9IjQ2MiIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMyI+VGhlIGJhbmQgaXMgbmFycm93IGFuZCB0aGUgb3JkZXIgaXMgdGhlIHdyb25nIG9uZTogRXJpZ29uLCB0aGUgTGlnaHRob3VzZSAzLjd4IG91dGxpZXIsIGlzIG5lYXIgdGhlIGJvdHRvbSwgYW5kIHRoZSBvcmRlciByZXNodWZmbGVzIGJldHdlZW4gZGVwbG95bWVudHMuIFRoaXMgaXMgYXJyaXZhbCwgbm90IHRoZSBFQy48L3RleHQ+CiAgPHRleHQgeD0iMTE1MiIgeT0iNDYyIiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0iZW5kIj5kb2NzLnN0ZXJldW1sYWJzLmNvbTwvdGV4dD4KPC9zdmc+Cg==" width="1200" height="480" class="img_ev3q"></p>
<table><thead><tr><th>Execution client</th><th>Mean arrival</th><th>90th pct</th><th>Blocks past 4 s (3 d)</th><th>Blocks timed</th></tr></thead><tbody><tr><td><strong>Besu</strong></td><td>1.94 s</td><td>3.43 s</td><td>37</td><td>11,801</td></tr><tr><td><strong>Erigon</strong></td><td>1.97 s</td><td>3.45 s</td><td>40</td><td>14,019</td></tr><tr><td><strong>Ethrex</strong></td><td>2.02 s</td><td>3.50 s</td><td>80</td><td>17,751</td></tr><tr><td><strong>Geth</strong></td><td>2.05 s</td><td>3.54 s</td><td>86</td><td>18,299</td></tr><tr><td><strong>Nethermind</strong></td><td>2.05 s</td><td>3.54 s</td><td>101</td><td>18,814</td></tr></tbody></table>
<p>The shape is healthy and close for everyone: blocks arrive around 2 seconds in on the mean, the 90th percentile sits near 3.5 seconds, and over three days each pairing logged 37 to 101 blocks past the 4-second line, out of twelve to nineteen thousand timed, between about a third and a half of a percent. (A note on the percentiles: because well under 1% of blocks cross 4 seconds and the bucket below it is 2 seconds wide, an interpolated 99th percentile sits just under 4 seconds for every client, an artifact of bucket width, not a per-client reading. The mean and the past-4-second count are exact.) Those late-arriving blocks are a network-and-proposer story, not an execution-client one: a block that shows up at 4.5 seconds was slow to reach the node, and no execution layer makes it earlier.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-blind-spot-arrival-cannot-rank-execution-clients">The blind spot: arrival cannot rank execution clients<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-nimbus#the-blind-spot-arrival-cannot-rank-execution-clients" class="hash-link" aria-label="Direct link to The blind spot: arrival cannot rank execution clients" title="Direct link to The blind spot: arrival cannot rank execution clients" translate="no">​</a></h2>
<p>Look down the table again. The five clients run from 1.94 to 2.05 seconds on the mean and from 37 to 101 blocks past 4 seconds, and that order does not match the execution ranking. The clearest tell is Erigon. Under Lighthouse, on the same NDC2 fleet and the same five execution clients (at slightly different versions, spelled out in the methodology), Erigon was the worst by a wide margin: the disk-bound <code>newPayload</code> tail that pushed its would-fail rate to 3.7x Geth's. Under Nimbus, Erigon has among the fewest late arrivals on the fleet, 40 in three days, second only to Besu. The execution outlier is unremarkable here, and the client with the most late arrivals, Nethermind, was middle of the pack on execution.</p>
<p><img decoding="async" loading="lazy" alt="The blind spot: under Lighthouse the same five execution clients spread 3.7x apart on would-fail rate, driven by execution; under Nimbus they fall into a narrow arrival band where Erigon, the Lighthouse outlier, is unremarkable" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDU0MCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNTQwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTIiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjYiIGZvbnQtd2VpZ2h0PSI3MDAiPlRoZSBzYW1lIGZpdmUgY2xpZW50cywgc2VlbiBieSB0d28gY29uc2Vuc3VzIGNsaWVudHM8L3RleHQ+CiAgPHRleHQgeD0iNDgiIHk9IjgyIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE2Ij5zYW1lIGV4ZWN1dGlvbiBjbGllbnRzIGFuZCBoYXJkd2FyZSBzcGVjIMK3IExpZ2h0aG91c2UgcmVzb2x2ZXMgYSAzLjd4IGV4ZWN1dGlvbiBzcHJlYWQ7IE5pbWJ1cydzIGFycml2YWwgbWV0cmljIGNhbm5vdDwvdGV4dD4KCiAgPCEtLSBkaXZpZGVyIC0tPgogIDxsaW5lIHgxPSI2MDAiIHkxPSIxMjAiIHgyPSI2MDAiIHkyPSI0MjAiIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIxIi8+CgogIDwhLS0gcGFuZWwgdGl0bGVzIC0tPgogIDx0ZXh0IHg9IjYwIiB5PSIxMjgiIGZpbGw9IiNlMmU4ZjQiIGZvbnQtc2l6ZT0iMTgiIGZvbnQtd2VpZ2h0PSI3MDAiPlVuZGVyIExpZ2h0aG91c2U8L3RleHQ+CiAgPHRleHQgeD0iNjAiIHk9IjE1MCIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxNCI+d291bGQtZmFpbCBhdHRlc3RhdGlvbnMgLyBkYXkgwrcgZXhlY3V0aW9uLWRyaXZlbjwvdGV4dD4KICA8dGV4dCB4PSI2NDAiIHk9IjEyOCIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxOCIgZm9udC13ZWlnaHQ9IjcwMCI+VW5kZXIgTmltYnVzPC90ZXh0PgogIDx0ZXh0IHg9IjY0MCIgeT0iMTUwIiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjE0Ij5ibG9ja3MgYXJyaXZpbmcgYWZ0ZXIgNCBzLCBvdmVyIDMgZGF5cyDCtyBhcnJpdmFsLWRyaXZlbjwvdGV4dD4KCiAgPCEtLSBmYWludCBwZXItY2xpZW50IGNvbm5lY3RpbmcgcnVsZXMgLS0+CiAgPGcgc3Ryb2tlPSIjMTYxZTQ0IiBzdHJva2Utd2lkdGg9IjEiPgogICAgPGxpbmUgeDE9IjYwIiB5MT0iMTg4IiB4Mj0iMTE0MCIgeTI9IjE4OCIvPgogICAgPGxpbmUgeDE9IjYwIiB5MT0iMjM4IiB4Mj0iMTE0MCIgeTI9IjIzOCIvPgogICAgPGxpbmUgeDE9IjYwIiB5MT0iMjg4IiB4Mj0iMTE0MCIgeTI9IjI4OCIvPgogICAgPGxpbmUgeDE9IjYwIiB5MT0iMzM4IiB4Mj0iMTE0MCIgeTI9IjMzOCIvPgogICAgPGxpbmUgeDE9IjYwIiB5MT0iMzg4IiB4Mj0iMTE0MCIgeTI9IjM4OCIvPgogIDwvZz4KCiAgPCEtLSBMRUZUOiBMaWdodGhvdXNlIHdvdWxkLWZhaWwvZGF5LiB4MD0xODUgc2NhbGUgMC41ODI1IHB4L3VuaXQgLS0+CiAgPHRleHQgeD0iMTc1IiB5PSIxOTIiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTUiIHRleHQtYW5jaG9yPSJlbmQiPkV0aHJleDwvdGV4dD4KICA8cmVjdCB4PSIxODUiIHk9IjE3NCIgd2lkdGg9Ijg3LjQiIGhlaWdodD0iMjgiIHJ4PSIzIiBmaWxsPSIjNzk4YmZmIi8+PHRleHQgeD0iMjgwIiB5PSIxOTMiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTMiPjE1MDwvdGV4dD4KICA8dGV4dCB4PSIxNzUiIHk9IjI0MiIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNSIgdGV4dC1hbmNob3I9ImVuZCI+R2V0aDwvdGV4dD4KICA8cmVjdCB4PSIxODUiIHk9IjIyNCIgd2lkdGg9Ijk3LjkiIGhlaWdodD0iMjgiIHJ4PSIzIiBmaWxsPSIjNzk4YmZmIi8+PHRleHQgeD0iMjkwIiB5PSIyNDMiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTMiPjE2ODwvdGV4dD4KICA8dGV4dCB4PSIxNzUiIHk9IjI5MiIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNSIgdGV4dC1hbmNob3I9ImVuZCI+TmV0aGVybWluZDwvdGV4dD4KICA8cmVjdCB4PSIxODUiIHk9IjI3NCIgd2lkdGg9IjEyNi40IiBoZWlnaHQ9IjI4IiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPjx0ZXh0IHg9IjMxOSIgeT0iMjkzIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjEzIj4yMTc8L3RleHQ+CiAgPHRleHQgeD0iMTc1IiB5PSIzNDIiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTUiIHRleHQtYW5jaG9yPSJlbmQiPkJlc3U8L3RleHQ+CiAgPHJlY3QgeD0iMTg1IiB5PSIzMjQiIHdpZHRoPSIxMzIuOCIgaGVpZ2h0PSIyOCIgcng9IjMiIGZpbGw9IiM3OThiZmYiLz48dGV4dCB4PSIzMjUiIHk9IjM0MyIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxMyI+MjI4PC90ZXh0PgogIDx0ZXh0IHg9IjE3NSIgeT0iMzkyIiBmaWxsPSIjZmI5MjNjIiBmb250LXNpemU9IjE1IiB0ZXh0LWFuY2hvcj0iZW5kIiBmb250LXdlaWdodD0iNzAwIj5Fcmlnb248L3RleHQ+CiAgPHJlY3QgeD0iMTg1IiB5PSIzNzQiIHdpZHRoPSIzNjAiIGhlaWdodD0iMjgiIHJ4PSIzIiBmaWxsPSIjZjk3MzE2Ii8+PHRleHQgeD0iNTM3IiB5PSIzOTMiIGZpbGw9IiMwZTE1MzAiIGZvbnQtc2l6ZT0iMTMiIGZvbnQtd2VpZ2h0PSI3MDAiIHRleHQtYW5jaG9yPSJlbmQiPjYxODwvdGV4dD4KCiAgPCEtLSBSSUdIVDogTmltYnVzIGJsb2NrcyBwYXN0IDRzIG92ZXIgMyBkYXlzLiB4MD03NjUgc2NhbGUgMi45NzAgcHgvdW5pdCAobWF4IDEwMSkgLS0+CiAgPHRleHQgeD0iNzU1IiB5PSIxOTIiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTUiIHRleHQtYW5jaG9yPSJlbmQiPkV0aHJleDwvdGV4dD4KICA8cmVjdCB4PSI3NjUiIHk9IjE3NCIgd2lkdGg9IjIzNy42IiBoZWlnaHQ9IjI4IiByeD0iMyIgZmlsbD0iIzc5OGJmZiIvPjx0ZXh0IHg9IjEwMTEiIHk9IjE5MyIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxMyI+ODA8L3RleHQ+CiAgPHRleHQgeD0iNzU1IiB5PSIyNDIiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTUiIHRleHQtYW5jaG9yPSJlbmQiPkdldGg8L3RleHQ+CiAgPHJlY3QgeD0iNzY1IiB5PSIyMjQiIHdpZHRoPSIyNTUuNCIgaGVpZ2h0PSIyOCIgcng9IjMiIGZpbGw9IiM3OThiZmYiLz48dGV4dCB4PSIxMDI5IiB5PSIyNDMiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTMiPjg2PC90ZXh0PgogIDx0ZXh0IHg9Ijc1NSIgeT0iMjkyIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE1IiB0ZXh0LWFuY2hvcj0iZW5kIj5OZXRoZXJtaW5kPC90ZXh0PgogIDxyZWN0IHg9Ijc2NSIgeT0iMjc0IiB3aWR0aD0iMzAwLjAiIGhlaWdodD0iMjgiIHJ4PSIzIiBmaWxsPSIjNzk4YmZmIi8+PHRleHQgeD0iMTA3NCIgeT0iMjkzIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjEzIj4xMDE8L3RleHQ+CiAgPHRleHQgeD0iNzU1IiB5PSIzNDIiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTUiIHRleHQtYW5jaG9yPSJlbmQiPkJlc3U8L3RleHQ+CiAgPHJlY3QgeD0iNzY1IiB5PSIzMjQiIHdpZHRoPSIxMDkuOSIgaGVpZ2h0PSIyOCIgcng9IjMiIGZpbGw9IiM3OThiZmYiLz48dGV4dCB4PSI4ODMiIHk9IjM0MyIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxMyI+Mzc8L3RleHQ+CiAgPHRleHQgeD0iNzU1IiB5PSIzOTIiIGZpbGw9IiNmYjkyM2MiIGZvbnQtc2l6ZT0iMTUiIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI3MDAiPkVyaWdvbjwvdGV4dD4KICA8cmVjdCB4PSI3NjUiIHk9IjM3NCIgd2lkdGg9IjExOC44IiBoZWlnaHQ9IjI4IiByeD0iMyIgZmlsbD0iI2Y5NzMxNiIvPjx0ZXh0IHg9Ijg5MiIgeT0iMzkzIiBmaWxsPSIjZmI5MjNjIiBmb250LXNpemU9IjEzIiBmb250LXdlaWdodD0iNzAwIj40MDwvdGV4dD4KCiAgPHRleHQgeD0iNDgiIHk9IjQ2MiIgZmlsbD0iI2ZkZTY4YSIgZm9udC1zaXplPSIxNSI+RXJpZ29uIChvcmFuZ2UpIHRvd2VycyBvbiB0aGUgbGVmdCBhbmQgaXMgYSBzaG9ydCBiYXIgb24gdGhlIHJpZ2h0OiB0aGUgZXhlY3V0aW9uIG91dGxpZXIgaXMgdW5yZW1hcmthYmxlIG9uIGFycml2YWwuPC90ZXh0PgogIDx0ZXh0IHg9IjQ4IiB5PSI0ODgiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTUiPlRoZSBleGVjdXRpb24gZ2FwIGlzIGdlbnVpbmU7IE5pbWJ1cydzIGFycml2YWwgaGlzdG9ncmFtIGNhbm5vdCBzZWUgaXQsIGJlY2F1c2UgYXJyaXZhbCBoYXBwZW5zIGJlZm9yZSB0aGUgZW5naW5lIGNhbGwuPC90ZXh0PgogIDx0ZXh0IHg9IjQ4IiB5PSI1MTIiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiPkRpZmZlcmVudCB3aW5kb3dzLCBtZXRyaWMgdHlwZXMgYW5kIHNsaWdodGx5IGRpZmZlcmVudCBFQyB2ZXJzaW9ucywgc2hvd24gdG8gY29udHJhc3Qgd2hhdCBlYWNoIGluc3RydW1lbnQgcmVzb2x2ZXMsIG5vdCBhIGNvbnRyb2xsZWQgaGVhZC10by1oZWFkLiBUaGUgcmlnaHQtcGFuZWwgb3JkZXIgdHJhY2tzIHRoZSBob3N0LCBub3QgdGhlIGNsaWVudCwgYW5kIHJlc2h1ZmZsZXMgYmV0d2VlbiBkZXBsb3ltZW50cy4gUmV0aCBleGNsdWRlZCAoc3luY2luZykuPC90ZXh0PgogIDx0ZXh0IHg9IjExNTIiIHk9IjUxMiIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9ImVuZCI+ZG9jcy5zdGVyZXVtbGFicy5jb208L3RleHQ+Cjwvc3ZnPgo=" width="1200" height="540" class="img_ev3q"></p>
<p>That is the whole point. If Nimbus's histogram were picking up the execution cost, Erigon's heavy <code>newPayload</code> tail would put it near the top here, the way it topped the would-fail count under Lighthouse. Instead it sits near the bottom. There is a genuine spread in the arrival numbers, but it is a host-and-network spread, not an execution one, and the giveaway is that it is not stable: in the previous deployment of this fleet the same metric put Besu at the top of the late-arrival count, and here Besu is at the bottom. That pairing even moved to a different Nimbus host between the two deployments, and a patch bump to Besu cannot change when Nimbus first hears a block over gossip, so what moved the number is the machine and where it sits in the network, not the execution client. Arrival is decided by a host's network position, peer set and local load, before the execution client is asked to verify anything, so it cannot carry the execution client's signature.</p>
<p>So an operator running Nimbus who asks "which execution client is eating my attestation timing" gets no answer from Nimbus. The histogram will show all of them arriving around 2 seconds and will look reassuring, while a 3.7x difference in how often the timing budget blows sits entirely in the slice Nimbus does not report.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-the-execution-slice-went-and-where-to-find-it">Where the execution slice went, and where to find it<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-nimbus#where-the-execution-slice-went-and-where-to-find-it" class="hash-link" aria-label="Direct link to Where the execution slice went, and where to find it" title="Direct link to Where the execution slice went, and where to find it" translate="no">​</a></h2>
<p>Nimbus has not hidden the execution time out of carelessness; it records block delay at arrival and leaves engine-API timing to the execution layer. So the number you want is on the execution-layer side of the engine API, and the coverage there is itself uneven. On our fleet, Nethermind exposes <code>nethermind_new_payload_execution_time</code> and Reth exposes <code>reth_consensus_engine_beacon_new_payload_latency</code>, both timing the engine call directly. The others surface per-block execution time mainly in their logs rather than as a clean metric: Geth's import lines carry an <code>elapsed</code> field, Ethrex's <code>[METRIC] BLOCK</code> entries a per-block time. There is no single cross-client <code>newPayload</code> panel to read; you assemble it from a different source per client, which is the same instrumentation-coverage gap one layer down, and the cut Lighthouse handed us for free by timing <code>newPayload</code> itself.</p>
<p>Some consensus clients do time the engine call themselves. Prysm, for one, publishes a per-execution-client <code>newPayload</code> latency histogram, the view Nimbus does not give, which a later edition will use. Nimbus does publish a second histogram, <code>validator_monitor_beacon_block_delay_seconds</code>, which is populated on our fleet, but it tracks block delay for monitored validators, an arrival-side measurement again, not the engine call, so it does not rescue the blind spot.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-to-measure-on-your-own-nimbus-nodes">What to measure on your own Nimbus nodes<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-nimbus#what-to-measure-on-your-own-nimbus-nodes" class="hash-link" aria-label="Direct link to What to measure on your own Nimbus nodes" title="Direct link to What to measure on your own Nimbus nodes" translate="no">​</a></h2>
<ul>
<li class=""><strong>Use the arrival histogram for what it is good at: proposer and network health.</strong> <code>beacon_block_delay</code> gives you a complete distribution of how late blocks reach this node. A drifting mean or a fattening 90th percentile is a peering or connectivity signal, and it is comparable across your pairings because arrival does not depend on the execution client. Our <a class="" href="https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis">peering deep dive</a> is where to take that.</li>
<li class=""><strong>Do not read the per-execution-client arrival spread as an execution-client ranking.</strong> As the Erigon inversion shows, the spread is host and network position, and it reshuffles when hosts change. If you switch execution client to chase a 0.1-second arrival difference, you will not get it, because you are not changing the thing that sets arrival.</li>
<li class=""><strong>For the execution slice, instrument the execution layer directly.</strong> Pull your execution client's own <code>newPayload</code> or block-processing timing and watch its tail, not its average. That is the lever the <a class="" href="https://docs.stereumlabs.com/blog/where-the-slot-goes-lighthouse">Lighthouse edition</a> found, and on Nimbus it is the only place that lever is visible.</li>
<li class=""><strong>Watch the outcome, not only the inputs.</strong> Attestation inclusion distance and attestation effectiveness, which most operators already track through rated.network or beaconcha.in, are what a blown timing budget shows up as. If those stay clean, a slightly fat arrival tail or a slow <code>newPayload</code> is not yet costing you duties; if they slip, the arrival histogram and the execution-layer timing together tell you which half of the slot to chase.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="coming-next-in-the-series">Coming next in the series<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-nimbus#coming-next-in-the-series" class="hash-link" aria-label="Direct link to Coming next in the series" title="Direct link to Coming next in the series" translate="no">​</a></h2>
<p>Two consensus clients down, and they already disagree on what a slot timing metric even is: Lighthouse times the execution slice but only samples it, Nimbus measures arrival in full but stops there. The next editions take the same question to Teku, Prysm, Lodestar and Grandine, and the pattern we are testing is that each one shows a different slice of the same slot. Where a client's instrumentation hides something its neighbours expose, that is the finding, and we will say so.</p>
<p>The comparison holds the hardware and the consensus client fixed and varies only the execution client. Lining clients up on equal footing across windows of uneven data quality, and catching when a node only looks synced, is an analysis in its own right rather than a lookup on a static panel, and it is what StereumLabs AI does on our fleet, on <a class="" href="https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack">the measurement stack we described here</a>. The same data lets you do this yourself: line specific clients up on matched versions and identical hardware, with StereumLabs AI as the analyst, instead of eyeballing two editions run weeks apart. If you run Ethereum infrastructure and want this lens on your own nodes, reach us at <a href="https://stereumlabs.com/" target="_blank" rel="noopener noreferrer" class="">stereumlabs.com</a> or <a href="mailto:contact@stereumlabs.com" target="_blank" rel="noopener noreferrer" class="">contact@stereumlabs.com</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="methodology">Methodology<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-nimbus#methodology" class="hash-link" aria-label="Direct link to Methodology" title="Direct link to Methodology" translate="no">​</a></h2>
<p>Numbers come from Nimbus's <code>beacon_block_delay</code> histogram on our NDC2 deployment (Vienna), queried on the <code>Prometheus-cold</code> datasource (uid <code>aez9ck4wz05q8e</code>), with the fleet labels documented in <a class="" href="https://docs.stereumlabs.com/docs/dashboards/build-your-own">build your own dashboards</a>. Per-client values are for <code>cc_client="nimbus-super", cc_version="multiarch-v26.6.0", deployment="NDC2"</code> grouped by <code>ec_client</code>, over the three days from 2026-06-27T00:00:00Z to 2026-06-30T00:00:00Z, with <code>increase(...[3d])</code> evaluated at the closing anchor so the counts are stable and reproducible rather than drifting with query time. This is the current deployment, which by this window had been running about six days, long enough for every mainstream execution client to be synced and steady throughout.</p>
<ul>
<li class=""><strong>Versions differ between the two editions, and we state it.</strong> The Lighthouse edition's window ran Besu 26.6.0, Erigon v3.4.3 and Ethrex 16.0.0; this Nimbus window runs Besu 26.6.1, Erigon v3.4.4 and Ethrex 17.0.0, with Geth v1.17.3 and Nethermind 1.38.1 identical in both (all confirmed from the datasource). Arrival is consensus-side and fixed before the execution client runs, so these differences do not move the arrival numbers here; they would matter for a direct execution-time comparison. Comparing specific execution clients head-to-head therefore wants matched versions on identical hardware, which is the version-pinned alignment StereumLabs and StereumLabs AI do across windows of version churn, and which you can run on your own pairings with the same data.</li>
<li class=""><strong>The metric</strong> is Nimbus's <code>beacon_block_delay</code> histogram (<code>_bucket/_sum/_count</code>), with buckets at 2, 4, 6, 8, 10, 12 and 14 seconds, in seconds. Nimbus records this delay when it first receives a block over gossip, before it hands the block to the execution layer to verify, so it is a block-arrival measurement. The cross-check that it is arrival and not a post-execution timestamp: its magnitude (around 2 s mean here) is in the range of Lighthouse's observed-arrival gauge on the same fleet, sits well below the execution-inclusive time-to-attestable, and does not move with execution-client speed.</li>
<li class=""><strong>The maths.</strong> The mean is <code>increase(_sum[3d]) / increase(_count[3d])</code>; the count past 4 seconds is <code>increase(_bucket{le="+Inf"}[3d]) - increase(_bucket{le="4.0"}[3d])</code>, exact because 4 seconds is a bucket boundary; quantiles are <code>histogram_quantile</code> over the same windowed buckets. Because the buckets are 2 seconds wide, the median and the 99th percentile are bucket-interpolated and approximate; the mean and the past-4-seconds count are not.</li>
<li class=""><strong>What the histogram counts, and why the per-client tail is not an execution ranking.</strong> Nimbus records this delay for blocks it received and timed on gossip, so the per-pairing counts (around 12,000 to 19,000 over roughly 21,600 slots) are a subset of all slots, and the share past 4 seconds is conditional on a block being timed rather than a per-slot miss rate. The per-client tail does show a spread (37 to 101 blocks past 4 seconds), but it tracks the host, not the execution client: it does not match the execution ranking, and the order is not stable across deployments. In the previous deployment of this fleet the same metric put Besu at the top of the late-arrival count; here Besu is at the bottom. That reshuffle is the signature of network position, not a client property.</li>
<li class=""><strong>Arrival is execution-client-independent, and we checked it both ways.</strong> The mean spans only 1.94 to 2.05 s across the five synced pairings, and the ordering does not match the execution ranking we measured under Lighthouse: Erigon, the Lighthouse would-fail outlier at 3.7x, has among the fewest late arrivals here. That non-correlation, together with the cross-deployment reshuffle, is the evidence that the spread is host and network position, not the execution client.</li>
<li class=""><strong>Sync was verified from logs, not metrics.</strong> For each pairing we read the execution client's own container logs across the window and confirmed it was importing at the chain tip: Geth's <code>Imported new potential chain segment</code> and <code>Chain head was updated</code> at the tip block, Besu's canonical block updates, Erigon's <code>head validated</code> and <code>Forkchoice Commit</code> with <code>initialCycle false</code>, Ethrex's <code>[METRIC] BLOCK</code> lines, Nethermind's <code>Valid. Result of New Block</code> at the tip. Reth was still in staged sync (<code>Executing stage 4/14</code> after six days on this deployment), so it is excluded; its <code>Received new payload</code> lines reach the tip number but only record that the consensus client offered the head, not that Reth had imported it. On identical 12-core hosts; consensus and validator processes run on separate machines.</li>
<li class=""><strong>Nimbus exposes no execution-side block-delay metric.</strong> The Lighthouse gauges <code>beacon_block_delay_execution_time</code>, <code>_consensus_verification_time</code>, <code>_attestable_slot_start</code> and the counter <code>_head_slot_start_exceeded_total</code> return no series for <code>cc_client="nimbus-super"</code>. This is the basis for the claim that Nimbus cannot rank execution clients on timing from its own metrics; the execution slice has to come from the execution client's own <code>newPayload</code> instrumentation.</li>
</ul>]]></content:encoded>
            <category>client comparison</category>
            <category>validator duties</category>
            <category>observability</category>
            <category>engine API</category>
            <category>Nimbus</category>
            <category>Lighthouse</category>
            <category>Geth</category>
            <category>Nethermind</category>
            <category>Besu</category>
            <category>Erigon</category>
            <category>Ethrex</category>
            <category>StereumLabs AI</category>
        </item>
        <item>
            <title><![CDATA[Where the slot goes: Lighthouse and attestation timing]]></title>
            <link>https://docs.stereumlabs.com/blog/where-the-slot-goes-lighthouse</link>
            <guid>https://docs.stereumlabs.com/blog/where-the-slot-goes-lighthouse</guid>
            <pubDate>Wed, 24 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Execution client choice shifts would-fail-attestation timing up to 3.7x under Lighthouse on identical hardware. We measure newPayload timing per EC.]]></description>
            <content:encoded><![CDATA[<p>An Ethereum slot is 12 seconds, and your attestation is due 4 seconds in. By the time your execution client sees a block to verify, most of that 4-second budget is already gone: on our fleet the block arrives, on average, <strong>1.7 to 1.9 seconds</strong> into the slot, and that number barely moves whichever execution client you run. What the execution client changes is the slice after arrival. Under Lighthouse, that slice runs from about <strong>100 ms (Ethrex) to 460 ms (Erigon)</strong> on a normal block. Across the mainstream clients it shifts how often the node lands late enough that attestations would fail by about <strong>1.5x</strong>, and by <strong>3.7x</strong> once Erigon's disk-bound tail is in the picture, on identical hardware.</p>
<p>This is the first of a series. We run all six execution clients paired with all six consensus clients on identical bare metal, and each consensus client reports slot timing differently. We start with Lighthouse because it instruments the block-delay breakdown more completely than any other CC on the fleet. Later editions take the same question to Prysm, Teku, Nimbus, Lodestar and Grandine.</p>
<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>Read this first</div><div class="admonitionContent_BuS1"><ul>
<li class=""><strong>"Would fail attestations" is a lateness flag, not a measured miss.</strong> Lighthouse derives this counter from block timing alone: it fires when a block lands late enough that a slot's attestation would be late, and it does so on our fleet even though we run no live validators on it. That is the tell that it is a block-processing heuristic, the same with validators or without, not a count of attestations missed or penalised. Read the per-pairing numbers as relative timing risk.</li>
<li class=""><strong>Reth is excluded.</strong> It has been back-filling across version upgrades through this window (currently v2.3.0) and was not at the tip; whether that is the client or our own deploy cadence is open (see <a class="" href="https://docs.stereumlabs.com/blog/ethereum-ec-hardware-footprint">the footprint census</a>). Its numbers are doubly an artifact of that state: the fastest execution time of any client (~39 ms) and the second-highest would-fail count both come from SYNCING-state replay rather than tip blocks, which is why it cannot sit in the comparison.</li>
<li class=""><strong>The outcome is a complete count; only the magnitudes are sampled.</strong> The would-fail-attestations rate is a monotonic counter, so the per-day numbers and the 3.7x are exact. The per-component execution times are gauges scraped about once a minute, so treat their p99 as a conservative floor. The full sampling detail, and why the tail claim rests on the counter rather than the gauge, is in the methodology.</li>
<li class=""><strong>Window and versions.</strong> Three days ending 2026-06-23, on Lighthouse v8.1.3 paired with Geth v1.17.3, Nethermind 1.38.1, Besu 26.6.0, Erigon v3.4.3, Ethrex 16.0.0. The fleet has since moved to Lighthouse v8.2.0, so reproducing this window means pinning the version (see methodology).</li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-4-second-deadline">The 4-second deadline<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-lighthouse#the-4-second-deadline" class="hash-link" aria-label="Direct link to The 4-second deadline" title="Direct link to The 4-second deadline" translate="no">​</a></h2>
<p>Attestations for a slot are due one-third of the way through it, at the 4-second mark, and the sync-committee message rides the same clock. Cross that line and the head vote is late: you lose the timely-head reward, and if late production then misses the inclusion windows for the source and target flags, those erode too, down to zero for the slot in the worst case. The attestation can still be included late, so this is a reward-erosion deadline, not a hard cutoff. So the question for an operator is not "did my node import the block" but "did it import the block, verify it, and make it attestable before 4 seconds were up." Everything below is measured against that line.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-the-12-seconds-go">Where the 12 seconds go<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-lighthouse#where-the-12-seconds-go" class="hash-link" aria-label="Direct link to Where the 12 seconds go" title="Direct link to Where the 12 seconds go" translate="no">​</a></h2>
<p>A block does not exist at your node at slot start. It is proposed elsewhere, gossiped across the network, and only then observed locally. Lighthouse records each step. Averaged over the window, the path to attestable looks like this:</p>
<p><img decoding="async" loading="lazy" alt="Slot timing under Lighthouse: the block is observed about 1.8 s into the slot, consensus verification adds ~0.16 s, execution-layer verification adds 0.1 to 0.46 s depending on the EC, and the block becomes attestable around 2.0 to 2.4 s, against the 4 s attestation deadline" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDQ3MCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNDcwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTQiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjciIGZvbnQtd2VpZ2h0PSI3MDAiPldoZXJlIHRoZSA0IHNlY29uZHMgZ28sIHVuZGVyIExpZ2h0aG91c2U8L3RleHQ+CiAgPHRleHQgeD0iNDgiIHk9Ijg0IiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE2Ij5hdmVyYWdlIGJsb2NrIMK3IHRpbWUgZnJvbSBzbG90IHN0YXJ0IHRvIGF0dGVzdGFibGUgwrcgdGhlIGF0dGVzdGF0aW9uIGlzIGR1ZSBhdCA0IHM8L3RleHQ+CgogIDwhLS0gbGVnZW5kIC0tPgogIDxyZWN0IHg9IjY0MCIgeT0iNDAiIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgcng9IjMiIGZpbGw9IiM1NDYwN2QiLz48dGV4dCB4PSI2NjIiIHk9IjUzIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0Ij5hcnJpdmFsIChuZXR3b3JrKTwvdGV4dD4KICA8cmVjdCB4PSI4MDAiIHk9IjQwIiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHJ4PSIzIiBmaWxsPSIjNzk4YmZmIi8+PHRleHQgeD0iODIyIiB5PSI1MyIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCI+Y29uc2Vuc3VzIHZlcmlmeTwvdGV4dD4KICA8cmVjdCB4PSI5NjAiIHk9IjQwIiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHJ4PSIzIiBmaWxsPSIjZjk3MzE2Ii8+PHRleHQgeD0iOTgyIiB5PSI1MyIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCI+ZXhlY3V0aW9uIChFTCk8L3RleHQ+CgogIDwhLS0gdGltZSBheGlzOiB4IDI0MC4uMTEzMCA9IDAuLjQuNXMgOyAxcyA9IDE5Ny43OHB4IC0tPgogIDxnIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIxIj4KICAgIDxsaW5lIHgxPSI0MzcuOCIgeTE9IjEyMCIgeDI9IjQzNy44IiB5Mj0iNDMwIi8+CiAgICA8bGluZSB4MT0iNjM1LjYiIHkxPSIxMjAiIHgyPSI2MzUuNiIgeTI9IjQzMCIvPgogICAgPGxpbmUgeDE9IjgzMy4zIiB5MT0iMTIwIiB4Mj0iODMzLjMiIHkyPSI0MzAiLz4KICA8L2c+CiAgPGxpbmUgeDE9IjEwMzEuMSIgeTE9IjEyMCIgeDI9IjEwMzEuMSIgeTI9IjQzMCIgc3Ryb2tlPSIjZjg3MTcxIiBzdHJva2Utd2lkdGg9IjIuNSIgc3Ryb2tlLWRhc2hhcnJheT0iNyA1Ii8+CiAgPHRleHQgeD0iMTAzMS4xIiB5PSIxMTMiIGZpbGw9IiNmY2E1YTUiIGZvbnQtc2l6ZT0iMTUiIHRleHQtYW5jaG9yPSJtaWRkbGUiPmF0dGVzdGF0aW9uIGRlYWRsaW5lIMK3IDQgczwvdGV4dD4KICA8ZyBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj4KICAgIDx0ZXh0IHg9IjI0MCIgeT0iNDUyIj4wPC90ZXh0Pjx0ZXh0IHg9IjQzNy44IiB5PSI0NTIiPjEgczwvdGV4dD48dGV4dCB4PSI2MzUuNiIgeT0iNDUyIj4yIHM8L3RleHQ+PHRleHQgeD0iODMzLjMiIHk9IjQ1MiI+MyBzPC90ZXh0Pjx0ZXh0IHg9IjEwMzEuMSIgeT0iNDUyIj40IHM8L3RleHQ+CiAgPC9nPgoKICA8IS0tIEdldGggYXZnOiBhcnJpdmFsIDAuLjEuODcgKDI0MC4uNjEwLjApLCBjb25zZW5zdXMgLi4yLjA0ICguLjY0My42KSwgZXhlYyAuLjIuMjQgKC4uNjgzLjEpIC0tPgogIDxnPgogICAgPHRleHQgeD0iMjI1IiB5PSIxNzIiIGZpbGw9IiNlMmU4ZjQiIGZvbnQtc2l6ZT0iMTYiIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI2MDAiPkdldGg8L3RleHQ+CiAgICA8cmVjdCB4PSIyNDAiIHk9IjE1MiIgd2lkdGg9IjM3MC4wIiBoZWlnaHQ9IjM0IiByeD0iMyIgZmlsbD0iIzU0NjA3ZCIvPgogICAgPHJlY3QgeD0iNjEwLjAiIHk9IjE1MiIgd2lkdGg9IjMzLjYiIGhlaWdodD0iMzQiIGZpbGw9IiM3OThiZmYiLz4KICAgIDxyZWN0IHg9IjY0My42IiB5PSIxNTIiIHdpZHRoPSIzOS41IiBoZWlnaHQ9IjM0IiByeD0iMyIgZmlsbD0iI2Y5NzMxNiIvPgogICAgPGxpbmUgeDE9IjY4My4xIiB5MT0iMTQ2IiB4Mj0iNjgzLjEiIHkyPSIxOTIiIHN0cm9rZT0iI2ZkZTY4YSIgc3Ryb2tlLXdpZHRoPSIyLjUiLz4KICAgIDx0ZXh0IHg9IjY5NCIgeT0iMTczIiBmaWxsPSIjZmRlNjhhIiBmb250LXNpemU9IjE0Ij5hZGRpdGl2ZSAyLjI0IHM8L3RleHQ+CiAgPC9nPgogIDwhLS0gRXJpZ29uIGF2ZzogYXJyaXZhbCAwLi4xLjY2ICgyNDAuLjU2OC4zKSwgY29uc2Vuc3VzIC4uMS44MyAoLi42MDEuOSksIGV4ZWMgLi4yLjI5ICguLjY5My4wKSAtLT4KICA8Zz4KICAgIDx0ZXh0IHg9IjIyNSIgeT0iMjQyIiBmaWxsPSIjZTJlOGY0IiBmb250LXNpemU9IjE2IiB0ZXh0LWFuY2hvcj0iZW5kIiBmb250LXdlaWdodD0iNjAwIj5Fcmlnb248L3RleHQ+CiAgICA8cmVjdCB4PSIyNDAiIHk9IjIyMiIgd2lkdGg9IjMyOC4zIiBoZWlnaHQ9IjM0IiByeD0iMyIgZmlsbD0iIzU0NjA3ZCIvPgogICAgPHJlY3QgeD0iNTY4LjMiIHk9IjIyMiIgd2lkdGg9IjMzLjYiIGhlaWdodD0iMzQiIGZpbGw9IiM3OThiZmYiLz4KICAgIDxyZWN0IHg9IjYwMS45IiB5PSIyMjIiIHdpZHRoPSI5MS4xIiBoZWlnaHQ9IjM0IiByeD0iMyIgZmlsbD0iI2Y5NzMxNiIvPgogICAgPGxpbmUgeDE9IjY5My4wIiB5MT0iMjE2IiB4Mj0iNjkzLjAiIHkyPSIyNjIiIHN0cm9rZT0iI2ZkZTY4YSIgc3Ryb2tlLXdpZHRoPSIyLjUiLz4KICAgIDx0ZXh0IHg9IjcwNCIgeT0iMjQzIiBmaWxsPSIjZmRlNjhhIiBmb250LXNpemU9IjE0Ij5hZGRpdGl2ZSAyLjI5IHM8L3RleHQ+CiAgPC9nPgogIDwhLS0gRXJpZ29uIHA5OSBleGVjOiBhcnJpdmFsIDAuLjEuNjYsIGNvbnNlbnN1cyAuLjEuODMgKDYwMS45KSwgZXhlYyArMi4xIC4uMy45MyAoMTAxNy41KSAtLT4KICA8Zz4KICAgIDx0ZXh0IHg9IjIyNSIgeT0iMzEyIiBmaWxsPSIjZTJlOGY0IiBmb250LXNpemU9IjE2IiB0ZXh0LWFuY2hvcj0iZW5kIiBmb250LXdlaWdodD0iNjAwIj5Fcmlnb248L3RleHQ+CiAgICA8dGV4dCB4PSIyMjUiIHk9IjMzMCIgZmlsbD0iIzhlOWJiZCIgZm9udC1zaXplPSIxMiIgdGV4dC1hbmNob3I9ImVuZCI+c2xvdyBibG9jazwvdGV4dD4KICAgIDxyZWN0IHg9IjI0MCIgeT0iMjkyIiB3aWR0aD0iMzI4LjMiIGhlaWdodD0iMzQiIHJ4PSIzIiBmaWxsPSIjNTQ2MDdkIi8+CiAgICA8cmVjdCB4PSI1NjguMyIgeT0iMjkyIiB3aWR0aD0iMzMuNiIgaGVpZ2h0PSIzNCIgZmlsbD0iIzc5OGJmZiIvPgogICAgPHJlY3QgeD0iNjAxLjkiIHk9IjI5MiIgd2lkdGg9IjQxNS42IiBoZWlnaHQ9IjM0IiByeD0iMyIgZmlsbD0iI2Y5NzMxNiIvPgogICAgPGxpbmUgeDE9IjEwMTcuNSIgeTE9IjI4NiIgeDI9IjEwMTcuNSIgeTI9IjMzMiIgc3Ryb2tlPSIjZmNhNWE1IiBzdHJva2Utd2lkdGg9IjIuNSIvPgogICAgPHRleHQgeD0iMTAxMCIgeT0iMjgwIiBmaWxsPSIjZmNhNWE1IiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0iZW5kIj4zLjkzIHMsIGF0IHRoZSBsaW5lPC90ZXh0PgogIDwvZz4KCiAgPHRleHQgeD0iMjQwIiB5PSIzODgiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTUiPk9uIGEgbm9ybWFsIGJsb2NrIGFsbCBjbGllbnRzIGFyZSBhdHRlc3RhYmxlIG5lYXIgMiBzLiBUaGUgZXhlY3V0aW9uIHRhaWwgaXMgd2hhdCBicnVzaGVzIDQgcy48L3RleHQ+CiAgPHRleHQgeD0iNDgiIHk9IjQzMCIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMyI+YXJyaXZhbCBhbmQgY29uc2Vuc3VzIGFyZSBlZmZlY3RpdmVseSBmaXhlZCBhY3Jvc3MgY2xpZW50czsgZXhlY3V0aW9uIGlzIHRoZSBzbGljZSB0aGUgRUMgc2V0czwvdGV4dD4KICA8dGV4dCB4PSIxMTUyIiB5PSI0MzAiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTMiIHRleHQtYW5jaG9yPSJlbmQiPmRvY3Muc3RlcmV1bWxhYnMuY29tPC90ZXh0Pgo8L3N2Zz4K" width="1200" height="470" class="img_ev3q"></p>
<p>The arithmetic is close to additive: time-to-attestable is roughly arrival plus consensus verification plus execution-layer verification. For Geth that is 1.87 + 0.17 + 0.20 = 2.24 s, against a measured attestable time of 2.28 s; for Erigon, 1.66 + 0.17 + 0.46 = 2.29 s against 2.31 s. The decomposition holds for every client, with a 30-to-40 ms residual for the availability and import steps Lighthouse times separately. The pieces:</p>
<table><thead><tr><th>Step</th><th>Duration</th><th>Set by</th></tr></thead><tbody><tr><td>Block arrival (observed from slot start)</td><td>1.66 to 1.87 s</td><td>the network and the proposer, not you</td></tr><tr><td>Consensus verification</td><td>~0.17 s</td><td>the consensus client, uniform here</td></tr><tr><td><strong>Execution-layer verification</strong></td><td><strong>0.10 to 0.46 s</strong></td><td><strong>the execution client you pick</strong></td></tr><tr><td>Becomes attestable</td><td>2.0 to 2.4 s</td><td>roughly arrival plus verification, with a small residual for availability and import steps Lighthouse times separately</td></tr></tbody></table>
<p>Two of those three rows are effectively fixed. Arrival is a network property: it ranges only from 1.66 to 1.87 s across the six pairings, and it does not track execution-client speed (Erigon, the slowest EC here, sees the earliest arrivals). Consensus verification is the same Lighthouse code in every pairing, around 165 ms throughout. The one row you choose is execution.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="execution-is-your-lever-newpayload-latency-by-client">Execution is your lever: newPayload latency by client<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-lighthouse#execution-is-your-lever-newpayload-latency-by-client" class="hash-link" aria-label="Direct link to Execution is your lever: newPayload latency by client" title="Direct link to Execution is your lever: newPayload latency by client" translate="no">​</a></h2>
<p>On a normal block the execution slice is small, 100 to 460 ms, comfortably inside the budget. Arrival is not your problem; this slice is. The risk lives in the tail, and the proof of the tail is the complete counter below, not the sampled magnitudes. For a sense of size, execution-layer verification on a single block reaches a sampled p99 of about 1.2 s on Geth, 1.5 s on Besu, and <strong>2.1 s on Erigon</strong> (a once-a-minute sample, so a conservative floor). The mechanism is plain: a slow <code>newPayload</code> tail landing on a block that already arrived late is what tips an otherwise marginal slot past 4 seconds. Stack a 2.1 s Erigon execution tail onto a 1.7 s arrival and you are near 3.8 s with consensus and import still to come.</p>
<p>It shows up in Lighthouse's own counter. <code>beacon_block_delay_head_slot_start_exceeded_total</code>, which Lighthouse describes as firing when "the duration between the start of the block's slot and the current time will result in failed attestations," counts the slots where the node landed too late to attest cleanly:</p>
<p><img decoding="async" loading="lazy" alt="Execution client attestation timing under Lighthouse: average newPayload verification time alongside the daily would-fail-attestations count, rising from Ethrex and Geth at the low end to Erigon at the high end" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDUyMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNTIwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTQiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjciIGZvbnQtd2VpZ2h0PSI3MDAiPkhvdyBvZnRlbiB0aGUgdGltaW5nIGJ1ZGdldCBibG93cywgdW5kZXIgTGlnaHRob3VzZTwvdGV4dD4KICA8dGV4dCB4PSI0OCIgeT0iODQiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTYiPnNsb3RzIHBlciBkYXkgdGhhdCB3b3VsZCBmYWlsIGF0dGVzdGF0aW9ucyDCtyAzLWRheSBhdmVyYWdlIMK3IHNhbWUgaGFyZHdhcmUsIHNhbWUgY29uc2Vuc3VzIGNsaWVudDwvdGV4dD4KCiAgPCEtLSB4IGF4aXM6IHggMzYwLi4xMTMwID0gMC4uNjUwIDsgMSB1bml0ID0gMS4xODQ2cHggLS0+CiAgPGcgc3Ryb2tlPSIjMWMyNjU0IiBzdHJva2Utd2lkdGg9IjEiPgogICAgPGxpbmUgeDE9IjM2MCIgeTE9IjExNiIgeDI9IjM2MCIgeTI9IjQ1MiIvPgogICAgPGxpbmUgeDE9IjU5Ni45IiB5MT0iMTE2IiB4Mj0iNTk2LjkiIHkyPSI0NTIiLz4KICAgIDxsaW5lIHgxPSI4MzMuOCIgeTE9IjExNiIgeDI9IjgzMy44IiB5Mj0iNDUyIi8+CiAgICA8bGluZSB4MT0iMTA3MC43IiB5MT0iMTE2IiB4Mj0iMTA3MC43IiB5Mj0iNDUyIi8+CiAgPC9nPgogIDxnIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJtaWRkbGUiPgogICAgPHRleHQgeD0iMzYwIiB5PSI0NzQiPjA8L3RleHQ+PHRleHQgeD0iNTk2LjkiIHk9IjQ3NCI+MjAwPC90ZXh0Pjx0ZXh0IHg9IjgzMy44IiB5PSI0NzQiPjQwMDwvdGV4dD48dGV4dCB4PSIxMDcwLjciIHk9IjQ3NCI+NjAwIC8gZGF5PC90ZXh0PgogIDwvZz4KCiAgPCEtLSBiYXJzIG9yZGVyZWQgYXNjZW5kaW5nIGJ5IHdvdWxkLWZhaWwvZGF5IDsgc2NhbGUgMS4xODQ2IHB4L3VuaXQgLS0+CiAgPCEtLSBFdGhyZXggMTUwIC0+IDE3Ny43IC0tPgogIDxnPgogICAgPHRleHQgeD0iMzQ1IiB5PSIxNTgiIGZpbGw9IiNlMmU4ZjQiIGZvbnQtc2l6ZT0iMTYiIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI2MDAiPkV0aHJleDwvdGV4dD4KICAgIDxyZWN0IHg9IjM2MCIgeT0iMTM2IiB3aWR0aD0iMTc3LjciIGhlaWdodD0iMzQiIHJ4PSI0IiBmaWxsPSIjNzk4YmZmIi8+CiAgICA8dGV4dCB4PSI1NDkiIHk9IjE1OCIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNSI+MTUwPC90ZXh0PgogICAgPHRleHQgeD0iMzYwIiB5PSIxOTAiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTMiPmV4ZWN1dGlvbiBhdmcgMTAzIG1zIMK3IHA5OSB+MS4xIHM8L3RleHQ+CiAgPC9nPgogIDwhLS0gR2V0aCAxNjggLT4gMTk5LjAgLS0+CiAgPGc+CiAgICA8dGV4dCB4PSIzNDUiIHk9IjIyOCIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxNiIgdGV4dC1hbmNob3I9ImVuZCIgZm9udC13ZWlnaHQ9IjYwMCI+R2V0aDwvdGV4dD4KICAgIDxyZWN0IHg9IjM2MCIgeT0iMjA2IiB3aWR0aD0iMTk5LjAiIGhlaWdodD0iMzQiIHJ4PSI0IiBmaWxsPSIjNzk4YmZmIi8+CiAgICA8dGV4dCB4PSI1NzEiIHk9IjIyOCIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNSI+MTY4PC90ZXh0PgogICAgPHRleHQgeD0iMzYwIiB5PSIyNjAiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTMiPmV4ZWN1dGlvbiBhdmcgMjAxIG1zIMK3IHA5OSB+MS4yIHM8L3RleHQ+CiAgPC9nPgogIDwhLS0gTmV0aGVybWluZCAyMTcgLT4gMjU3LjEgLS0+CiAgPGc+CiAgICA8dGV4dCB4PSIzNDUiIHk9IjI5OCIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxNiIgdGV4dC1hbmNob3I9ImVuZCIgZm9udC13ZWlnaHQ9IjYwMCI+TmV0aGVybWluZDwvdGV4dD4KICAgIDxyZWN0IHg9IjM2MCIgeT0iMjc2IiB3aWR0aD0iMjU3LjEiIGhlaWdodD0iMzQiIHJ4PSI0IiBmaWxsPSIjNzk4YmZmIi8+CiAgICA8dGV4dCB4PSI2MjkiIHk9IjI5OCIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNSI+MjE3PC90ZXh0PgogICAgPHRleHQgeD0iMzYwIiB5PSIzMzAiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTMiPmV4ZWN1dGlvbiBhdmcgMTY1IG1zIMK3IHA5OSB+MS4xIHM8L3RleHQ+CiAgPC9nPgogIDwhLS0gQmVzdSAyMjggLT4gMjcwLjEgLS0+CiAgPGc+CiAgICA8dGV4dCB4PSIzNDUiIHk9IjM2OCIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxNiIgdGV4dC1hbmNob3I9ImVuZCIgZm9udC13ZWlnaHQ9IjYwMCI+QmVzdTwvdGV4dD4KICAgIDxyZWN0IHg9IjM2MCIgeT0iMzQ2IiB3aWR0aD0iMjcwLjEiIGhlaWdodD0iMzQiIHJ4PSI0IiBmaWxsPSIjNzk4YmZmIi8+CiAgICA8dGV4dCB4PSI2NDIiIHk9IjM2OCIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNSI+MjI4PC90ZXh0PgogICAgPHRleHQgeD0iMzYwIiB5PSI0MDAiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTMiPmV4ZWN1dGlvbiBhdmcgMjk3IG1zIMK3IHA5OSB+MS41IHM8L3RleHQ+CiAgPC9nPgogIDwhLS0gRXJpZ29uIDYxOCAtPiA3MzIuMSAtLT4KICA8Zz4KICAgIDx0ZXh0IHg9IjM0NSIgeT0iNDM4IiBmaWxsPSIjZTJlOGY0IiBmb250LXNpemU9IjE2IiB0ZXh0LWFuY2hvcj0iZW5kIiBmb250LXdlaWdodD0iNjAwIj5Fcmlnb248L3RleHQ+CiAgICA8cmVjdCB4PSIzNjAiIHk9IjQxNiIgd2lkdGg9IjczMi4xIiBoZWlnaHQ9IjM0IiByeD0iNCIgZmlsbD0iI2Y5NzMxNiIvPgogICAgPHRleHQgeD0iMTA4MiIgeT0iNDM4IiBmaWxsPSIjMGUxNTMwIiBmb250LXNpemU9IjE1IiBmb250LXdlaWdodD0iNzAwIiB0ZXh0LWFuY2hvcj0iZW5kIj42MTg8L3RleHQ+CiAgICA8dGV4dCB4PSIzNjAiIHk9IjQwMCIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMyI+PC90ZXh0PgogIDwvZz4KICA8dGV4dCB4PSIzNjAiIHk9IjQzOCIgZmlsbD0iIzBlMTUzMCIgZm9udC1zaXplPSIxMyIgb3BhY2l0eT0iMCI+PC90ZXh0PgoKICA8dGV4dCB4PSI0OCIgeT0iNDk0IiBmaWxsPSIjZmI5MjNjIiBmb250LXNpemU9IjEzIj5Fcmlnb246IGV4ZWN1dGlvbiBhdmcgNDU3IG1zIMK3IHA5OSB+Mi4xIHMuIE1haW5zdHJlYW0gY2xpZW50cyBzcGFuIH4xLjV4ICgxNTAgdG8gMjI4L2RheSk7IEVyaWdvbidzIGRpc2stYm91bmQgdGFpbCBwdXNoZXMgaXQgdG8gfjMuN3ggR2V0aC48L3RleHQ+CiAgPHRleHQgeD0iNDgiIHk9IjUxNCIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMiI+UmV0aCBleGNsdWRlZCAocmVzeW5jaW5nKSDCtyAid291bGQgZmFpbCBhdHRlc3RhdGlvbnMiIGlzIExpZ2h0aG91c2UncyBsYXRlbmVzcyBoZXVyaXN0aWMsIG5vdCBhIG1lYXN1cmVkIG1pc3M7IG5vIGxpdmUgdmFsaWRhdG9yczwvdGV4dD4KICA8dGV4dCB4PSIxMTUyIiB5PSI1MTQiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTIiIHRleHQtYW5jaG9yPSJlbmQiPmRvY3Muc3RlcmV1bWxhYnMuY29tPC90ZXh0Pgo8L3N2Zz4K" width="1200" height="520" class="img_ev3q"></p>
<table><thead><tr><th>Execution client</th><th>Execution verify, avg</th><th>Execution verify, p99*</th><th>Would-fail-attestations, per day</th></tr></thead><tbody><tr><td><strong>Ethrex</strong></td><td>103 ms</td><td>~1.1 s</td><td>150</td></tr><tr><td><strong>Geth</strong></td><td>201 ms</td><td>~1.2 s</td><td>168</td></tr><tr><td><strong>Nethermind</strong></td><td>165 ms</td><td>~1.1 s</td><td>217</td></tr><tr><td><strong>Besu</strong></td><td>297 ms</td><td>~1.5 s</td><td>228</td></tr><tr><td><strong>Erigon</strong></td><td>457 ms</td><td>~2.1 s</td><td>618</td></tr></tbody></table>
<p>*p99 of the once-a-minute samples, a conservative floor. The tail claim rests on the complete would-fail counter, not this column.</p>
<p>The extremes line up: the fastest-tail clients (Ethrex, Geth) sit lowest at around 150 to 170 a day, and Erigon, with the heaviest tail, sits at 618, about 3.7x as often, on the same hardware behind the same Lighthouse with the same arrival times. The four mainstream clients span 150 to 228 a day, about 1.5x; Erigon's disk-bound tail is what stretches that to 3.7x. In slot terms, 618 a day is about 8.6% of slots flagged on Erigon against 2.3% on Geth. The middle is not strictly ordered by the average, and that is the point: Nethermind's average execution is below Geth's, yet it lands late more often. The mean is comfortable for every client; the tail is what sets the miss rate, which is why the p99 column matters more than the average. The control holds at the tail too: arrival's p99 is 3.3 to 3.5 s across all six pairings and does not order by execution-client speed (Geth's arrival tail is the highest, Erigon's among the lowest), so the would-fail gap is the execution layer's to own.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-erigon-has-the-highest-newpayload-latency-tail">Why Erigon has the highest newPayload latency tail<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-lighthouse#why-erigon-has-the-highest-newpayload-latency-tail" class="hash-link" aria-label="Direct link to Why Erigon has the highest newPayload latency tail" title="Direct link to Why Erigon has the highest newPayload latency tail" translate="no">​</a></h2>
<p>This is the same Erigon that, in <a class="" href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour">our pruning census</a>, runs its pruning on the engine-API hot path, and the same Erigon that in <a class="" href="https://docs.stereumlabs.com/blog/ethereum-ec-hardware-footprint">the hardware-footprint census</a> sustains the fleet's highest disk writes (about 1.9 TB a day). Heavy, continuous disk work is the most likely driver of the tail of a <code>newPayload</code> call: most are fast, but the ones that land during a flush or compaction are slow, and those are the blocks that miss. We have not yet lined up individual slow-<code>newPayload</code> timestamps against Erigon's compaction windows; a later edition will. The trade Erigon makes for the smallest disk footprint on the fleet shows up again here, on the timing budget.</p>
<p>To be fair across the board: on a typical block every one of these clients is comfortably attestable around 2 seconds, half the budget to spare. None of them is "too slow" in the average case. The difference is entirely in how often the tail bites, and that is what the per-day counter captures. Besu sits one step down in the same regime: the second-heaviest tail (p99 ~1.5 s, 297 ms average) for the same disk reason, just biting less often than Erigon's. It is a gradient, not one villain.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-honest-version-of-blame-your-el">The honest version of "blame your EL"<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-lighthouse#the-honest-version-of-blame-your-el" class="hash-link" aria-label="Direct link to The honest version of &quot;blame your EL&quot;" title="Direct link to The honest version of &quot;blame your EL&quot;" translate="no">​</a></h2>
<p>Look at a single late block and the execution client usually looks innocent. In Lighthouse's DEBUG log, a delayed head block typically reads like <code>observed_delay_ms: 7194, consensus_time_ms: 236, execution_time_ms: 80</code>: the block showed up 7 seconds into the slot, and the local node handled it in a few hundred milliseconds. The lateness was the proposer's or the network's, and no execution client would have saved that slot.</p>
<p><img decoding="async" loading="lazy" alt="Anatomy of a single late block under Lighthouse: the block arrives 7.2 seconds into the slot, already past the 4-second deadline, while the node&amp;#39;s own consensus and execution verification together take only about 0.3 seconds" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDM4MCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iMzgwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTAiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjYiIGZvbnQtd2VpZ2h0PSI3MDAiPkFuYXRvbXkgb2YgYSBsYXRlIGJsb2NrPC90ZXh0PgogIDx0ZXh0IHg9IjQ4IiB5PSI3OCIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxNiI+YSBzaW5nbGUgZGVsYXllZC1oZWFkIGJsb2NrIGZyb20gTGlnaHRob3VzZSdzIERFQlVHIGxvZzogdGhlIGxhdGVuZXNzIGlzIHVwc3RyZWFtLCBub3QgdGhlIGV4ZWN1dGlvbiBsYXllcjwvdGV4dD4KCiAgPCEtLSBsZWdlbmQgLS0+CiAgPHJlY3QgeD0iNzAwIiB5PSIzOCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiByeD0iMyIgZmlsbD0iIzU0NjA3ZCIvPjx0ZXh0IHg9IjcyMiIgeT0iNTEiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTQiPmFycml2YWwgKG5ldHdvcmspPC90ZXh0PgogIDxyZWN0IHg9Ijg2MCIgeT0iMzgiIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgcng9IjMiIGZpbGw9IiM3OThiZmYiLz48dGV4dCB4PSI4ODIiIHk9IjUxIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0Ij5jb25zZW5zdXM8L3RleHQ+CiAgPHJlY3QgeD0iOTgwIiB5PSIzOCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiByeD0iMyIgZmlsbD0iI2Y5NzMxNiIvPjx0ZXh0IHg9IjEwMDIiIHk9IjUxIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0Ij5leGVjdXRpb248L3RleHQ+CgogIDwhLS0gdGltZSBheGlzIHggMjQwLi4xMTMwID0gMC4uMTBzIDsgMXMgPSA4OXB4IC0tPgogIDxnIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIxIj4KICAgIDxsaW5lIHgxPSI0MTgiIHkxPSIxMjAiIHgyPSI0MTgiIHkyPSIzMDAiLz4KICAgIDxsaW5lIHgxPSI3NzQiIHkxPSIxMjAiIHgyPSI3NzQiIHkyPSIzMDAiLz4KICAgIDxsaW5lIHgxPSI5NTIiIHkxPSIxMjAiIHgyPSI5NTIiIHkyPSIzMDAiLz4KICAgIDxsaW5lIHgxPSIxMTMwIiB5MT0iMTIwIiB4Mj0iMTEzMCIgeTI9IjMwMCIvPgogIDwvZz4KICA8bGluZSB4MT0iNTk2IiB5MT0iMTIwIiB4Mj0iNTk2IiB5Mj0iMzAwIiBzdHJva2U9IiNmODcxNzEiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtZGFzaGFycmF5PSI3IDUiLz4KICA8dGV4dCB4PSI1OTYiIHk9IjExMyIgZmlsbD0iI2ZjYTVhNSIgZm9udC1zaXplPSIxNSIgdGV4dC1hbmNob3I9Im1pZGRsZSI+YXR0ZXN0YXRpb24gZGVhZGxpbmUgwrcgNCBzPC90ZXh0PgogIDxnIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJtaWRkbGUiPgogICAgPHRleHQgeD0iMjQwIiB5PSIzMjIiPjA8L3RleHQ+PHRleHQgeD0iNDE4IiB5PSIzMjIiPjIgczwvdGV4dD48dGV4dCB4PSI1OTYiIHk9IjMyMiI+NCBzPC90ZXh0Pjx0ZXh0IHg9Ijc3NCIgeT0iMzIyIj42IHM8L3RleHQ+PHRleHQgeD0iOTUyIiB5PSIzMjIiPjggczwvdGV4dD48dGV4dCB4PSIxMTMwIiB5PSIzMjIiPjEwIHM8L3RleHQ+CiAgPC9nPgoKICA8IS0tIHRoZSBibG9jazogYXJyaXZhbCAwLi43LjE5NCAoMjQwLi44ODAuMyksIGNvbnNlbnN1cyAuLjcuNDMgKC4uOTAxLjMpLCBleGVjdXRpb24gLi43LjUxICguLjkwOC40KSwgaW1wb3J0IHRvIGhlYWQgOS4yNzggKC4uMTA2NS43KSAtLT4KICA8cmVjdCB4PSIyNDAiIHk9IjE2MCIgd2lkdGg9IjY0MC4zIiBoZWlnaHQ9IjQ4IiByeD0iNCIgZmlsbD0iIzU0NjA3ZCIvPgogIDxyZWN0IHg9Ijg4MC4zIiB5PSIxNjAiIHdpZHRoPSIyMS4wIiBoZWlnaHQ9IjQ4IiBmaWxsPSIjNzk4YmZmIi8+CiAgPHJlY3QgeD0iOTAxLjMiIHk9IjE2MCIgd2lkdGg9IjcuMSIgaGVpZ2h0PSI0OCIgZmlsbD0iI2Y5NzMxNiIvPgogIDxyZWN0IHg9IjkwOC40IiB5PSIxNjAiIHdpZHRoPSIxNTcuMyIgaGVpZ2h0PSI0OCIgcng9IjQiIGZpbGw9IiMyMjJjNGQiLz4KICA8dGV4dCB4PSI1NjAiIHk9IjE5MCIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxNyIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZm9udC13ZWlnaHQ9IjYwMCI+YmxvY2sgYXJyaXZhbDogNy4yIHM8L3RleHQ+CiAgPHRleHQgeD0iOTg3IiB5PSIxOTAiIGZpbGw9IiM2Yjc3OTkiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJtaWRkbGUiPmltcG9ydDwvdGV4dD4KICA8bGluZSB4MT0iMTA2NS43IiB5MT0iMTU0IiB4Mj0iMTA2NS43IiB5Mj0iMjE0IiBzdHJva2U9IiNmZGU2OGEiIHN0cm9rZS13aWR0aD0iMi41Ii8+CiAgPHRleHQgeD0iMTA3NSIgeT0iMTkwIiBmaWxsPSIjZmRlNjhhIiBmb250LXNpemU9IjE0Ij5oZWFkIDkuMyBzPC90ZXh0PgoKICA8IS0tIGNhbGxvdXQ6IGFycml2YWwgYWxyZWFkeSBwYXN0IGRlYWRsaW5lIC0tPgogIDx0ZXh0IHg9Ijg4MCIgeT0iMTQ2IiBmaWxsPSIjZmNhNWE1IiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0iZW5kIj5hbHJlYWR5IDMuMiBzIHBhc3QgdGhlIGRlYWRsaW5lIHdoZW4gaXQgYXJyaXZlZDwvdGV4dD4KCiAgPCEtLSBjYWxsb3V0OiB0aW55IHZlcmlmeSBzbGljZSAtLT4KICA8bGluZSB4MT0iOTA1IiB5MT0iMjA4IiB4Mj0iOTA1IiB5Mj0iMjUwIiBzdHJva2U9IiM4ZTliYmQiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgPHRleHQgeD0iOTA1IiB5PSIyNzAiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJtaWRkbGUiPmNvbnNlbnN1cyAyMzYgbXMgKyBleGVjdXRpb24gODAgbXM8L3RleHQ+CgogIDx0ZXh0IHg9IjQ4IiB5PSIzNTIiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTUiPlRoZSBibG9jayB3YXMgNyBzIGxhdGUgZnJvbSB0aGUgbmV0d29yay4gVGhlIG5vZGUncyBvd24gdmVyaWZpY2F0aW9uIHdhcyBhYm91dCAwLjMgcy4gTm8gZXhlY3V0aW9uIGNsaWVudCBzYXZlcyB0aGlzIHNsb3QuPC90ZXh0PgogIDx0ZXh0IHg9IjExNTIiIHk9IjM1MiIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9ImVuZCI+ZG9jcy5zdGVyZXVtbGFicy5jb208L3RleHQ+Cjwvc3ZnPgo=" width="1200" height="380" class="img_ev3q"></p>
<p>So why does the execution client move the daily count by 3.7x? Because it is not about the catastrophically late blocks, it is about the marginal ones. Across thousands of slots, a meaningful fraction arrive late enough that a few hundred extra milliseconds of execution is the difference between attestable-in-time and not. A faster execution layer does not fix a 7-second-late block, but it rescues the slots that were close. That is the lever you hold.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-to-measure-on-your-own-nodes">What to measure on your own nodes<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-lighthouse#what-to-measure-on-your-own-nodes" class="hash-link" aria-label="Direct link to What to measure on your own nodes" title="Direct link to What to measure on your own nodes" translate="no">​</a></h2>
<ul>
<li class=""><strong>Pull <code>beacon_block_delay_observed_slot_start</code> per pairing.</strong> If your blocks arrive late on average, that is a peering or proposer-connectivity problem, not an execution-client one, and changing EC will not help. Our <a class="" href="https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis">peering deep dive</a> is the place to start on that.</li>
<li class=""><strong>Pull <code>beacon_block_delay_execution_time</code> and watch its p99, not its average.</strong> The average is fine for everyone; the tail is where duties are lost.</li>
<li class=""><strong>Track <code>beacon_block_delay_head_slot_start_exceeded_total</code> as a rate.</strong> It is the closest single number to "how often is my timing budget blown," and it is comparable across your own pairings, as long as you pin one consensus-client version per comparison so a mid-window upgrade does not pool two code paths.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="coming-next-in-the-series">Coming next in the series<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-lighthouse#coming-next-in-the-series" class="hash-link" aria-label="Direct link to Coming next in the series" title="Direct link to Coming next in the series" translate="no">​</a></h2>
<p>Lighthouse gives the cleanest breakdown, which is why it is first. The other consensus clients expose this timing differently, and that difference is itself a finding: the next editions take the same slot-timing question to Prysm, Teku, Nimbus, Lodestar and Grandine, and where their instrumentation hides things Lighthouse shows, we will say so.</p>
<p>This comparison holds the hardware and the consensus client fixed and varies only the execution client, which is the cut that makes the execution layer's contribution legible. Lining clients up on truly equal footing across windows of uneven data quality is an analysis in its own right, not a lookup on a static panel, and it is what StereumLabs AI does on our fleet, on <a class="" href="https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack">the measurement stack we described here</a>. When one pairing stops matching its siblings, that divergence is a finding, sometimes <a class="" href="https://docs.stereumlabs.com/blog/besu-bonsai-layered-storage-memory-leak">an upstream bug report</a>. If you run Ethereum infrastructure and want this lens on your own nodes, reach us at <a href="https://stereumlabs.com/" target="_blank" rel="noopener noreferrer" class="">stereumlabs.com</a> or <a href="mailto:contact@stereumlabs.com" target="_blank" rel="noopener noreferrer" class="">contact@stereumlabs.com</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="methodology">Methodology<a href="https://docs.stereumlabs.com/blog/where-the-slot-goes-lighthouse#methodology" class="hash-link" aria-label="Direct link to Methodology" title="Direct link to Methodology" translate="no">​</a></h2>
<p>Numbers come from Lighthouse's <code>beacon_block_delay_*</code> metrics on our NDC2 deployment (Vienna), queried on the <code>Prometheus-cold</code> datasource (uid <code>aez9ck4wz05q8e</code>), with the fleet labels documented in <a class="" href="https://docs.stereumlabs.com/docs/dashboards/build-your-own">build your own dashboards</a>. Per-client values are for <code>cc_client="lighthouse-super", cc_version="v8.1.3", deployment="NDC2"</code> grouped by <code>ec_client</code>. The would-fail counter rates are <code>increase(...[3d])</code> evaluated at 2026-06-23T00:00:00Z, so they are stable and reproducible rather than drifting with the query time. The fleet has since moved to Lighthouse v8.2.0, so pinning one CC version per comparison is what reproduces this window. Pinning <code>deployment="NDC2"</code> also keeps the bare-metal Vienna hosts from being pooled with a second Geth set on GCP, which sees the same block-arrival time (~1.88 s) but lands late about 303 times a day against the NDC2 host's 168, a platform effect of the cloud host rather than the network or the client.</p>
<ul>
<li class=""><strong>Components</strong> are the Lighthouse gauges <code>beacon_block_delay_observed_slot_start</code> (arrival), <code>beacon_block_delay_consensus_verification_time</code>, <code>beacon_block_delay_execution_time</code> (execution-layer verification), and <code>beacon_block_delay_attestable_slot_start</code> (time to attestable). All are in milliseconds, confirmed against Lighthouse's DEBUG block-delay logs which label the same fields <code>_ms</code>.</li>
<li class=""><strong>Sampling.</strong> The component gauges are scraped about once every 66 seconds, so each value is one sampled block rather than a full per-block stream. Averages over three days are unbiased; the sampled <code>quantile_over_time</code> p99 and <code>max_over_time</code> worst-case are conservative floors, since between-scrape spikes are missed. We do not lean on them: the tail is carried by the complete would-fail counter. A precise percentile would need a histogram, which Lighthouse does not expose for these gauges (Nimbus does, so the Nimbus edition can use it).</li>
<li class=""><strong>The would-fail-attestations figure</strong> is <code>increase(beacon_block_delay_head_slot_start_exceeded_total[3d]) / 3</code>, per <code>ec_client</code>. Lighthouse's own help text defines this counter as triggering "when the duration between the start of the block's slot and the current time will result in failed attestations." Unlike the block-delay gauges, this is a monotonic counter, so the per-day counts are complete rather than sampled; only the execution average and p99 columns are the once-a-minute samples. It fires from block timing regardless of validators (it increments on our fleet with none attached), so it is Lighthouse's lateness heuristic, not an observed miss count, and it is a binary flag rather than an inclusion-or-penalty outcome: a flagged slot can still attest late. Read the counts as relative risk between pairings, not as absolute missed duties. Attaching live validators would not move these numbers: the counter times block import, which is independent of attestation signing, aggregation and local block production.</li>
<li class=""><strong>Arrival is EC-independent.</strong> <code>beacon_block_delay_observed_slot_start</code> ranges 1.66 to 1.87 s across the six pairings and does not order by execution-client speed, which is why we attribute the would-fail differences to execution rather than to the network or host.</li>
<li class=""><strong>Reth is excluded</strong> from the comparison: it was resyncing throughout (v2.3.0, finish stage at zero, zero <code>VALID</code> forkchoice responses over 24 h), so its block-delay metrics are not those of a synced node; <a class="" href="https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026">the sync-speed census</a> covers from-scratch sync times client by client. On identical 12-core hosts; consensus and validator processes run on separate machines.</li>
</ul>]]></content:encoded>
            <category>client comparison</category>
            <category>validator duties</category>
            <category>observability</category>
            <category>engine API</category>
            <category>Lighthouse</category>
            <category>Geth</category>
            <category>Nethermind</category>
            <category>Besu</category>
            <category>Erigon</category>
            <category>Ethrex</category>
            <category>StereumLabs AI</category>
        </item>
        <item>
            <title><![CDATA[Ethereum execution client hardware footprint, measured]]></title>
            <link>https://docs.stereumlabs.com/blog/ethereum-ec-hardware-footprint</link>
            <guid>https://docs.stereumlabs.com/blog/ethereum-ec-hardware-footprint</guid>
            <pubDate>Wed, 17 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Six Ethereum execution clients on identical 12-core hosts: 5 to 16 GiB RAM, half a CPU core at the tip, and disk writes from 0.9 to 22 MB/s.]]></description>
            <content:encoded><![CDATA[<p>How much machine does an Ethereum execution client need once it sits at the tip of mainnet? Our fleet runs every major execution client on its own host, all with 12 cores, five of six client sets with 16 GiB RAM, one consensus client per pairing on a separate machine. Same chain, same engine-API traffic, one telemetry pipeline. Averaged over the same 36 hours, the synced clients hold between <strong>4.9 and 15.6 GiB</strong> of host memory, burn <strong>about half a CPU core</strong>, and write to disk at anywhere from <strong>0.9 to 22 MB/s</strong>. The spread is the story: the client you pick decides whether your box idles or works.</p>
<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>Read this first</div><div class="admonitionContent_BuS1"><ul>
<li class=""><strong>Validator-client traffic is mirrored, not live.</strong> During this window, every consensus client received a copy of the requests our validator clients send to production nodes. Each pairing therefore carries the request load of a staking node, including the duty-driven engine-API work that reaches the execution client; no keys live on this fleet and nothing signs from it.</li>
<li class=""><strong>Reth's row is from an earlier synced version.</strong> The Reth version on our hosts during the June window was mid-resync, so its numbers come from v1.11.3, the last time Reth fully synced on this fleet (four days ending 2026-04-23). It is labeled wherever it appears; the other five are the June window.</li>
<li class=""><strong>Ethrex runs on 64 GiB hosts.</strong> Its working set does not fit the 16 GiB envelope the other five live in. Details below.</li>
<li class=""><strong>One window, young hosts.</strong> All numbers are 36-hour averages ending 2026-06-11 ~15:00 UTC; host uptimes were 2 to 8 days. Treat them as a snapshot of these versions, not eternal constants.</li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-fleet-and-what-we-measured">The fleet, and what we measured<a href="https://docs.stereumlabs.com/blog/ethereum-ec-hardware-footprint#the-fleet-and-what-we-measured" class="hash-link" aria-label="Direct link to The fleet, and what we measured" title="Direct link to The fleet, and what we measured" translate="no">​</a></h2>
<p>Each execution client runs six times, once per consensus-client partner (Prysm, Lighthouse, Teku, Nimbus, Lodestar, Grandine, all supernodes on their own hosts; <a class="" href="https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes">Fusaka's hardware impact</a> is a separate post). The EC host runs the execution client, a node exporter, and a log shipper, nothing else. So host-level telemetry is, to a close approximation, the execution client's footprint, measured the same way for all six clients. Per-client numbers below average across the six pairings.</p>
<p>Versions in the June window: Geth v1.17.3, Nethermind 1.38.0, Besu 26.6.0, Erigon v3.4.3, Ethrex 15.0.0. Sync state was verified from container logs, not just metrics; all five were importing blocks at the live tip (block ~25,294,900) during the window. Reth ran v2.2.0 then but was mid-resync, so its row is taken from v1.11.3 in April, the last time it was synced on this fleet (see below).</p>
<table><thead><tr><th>Client</th><th>RAM avg</th><th>RAM peak</th><th>CPU avg</th><th>Busiest 30 min</th><th>Disk read</th><th>Disk write</th><th>P2P rx / tx</th></tr></thead><tbody><tr><td><strong>Nethermind</strong></td><td>4.9 GiB</td><td>6.2 GiB</td><td>0.53 cores</td><td>0.78 cores</td><td>1.4 MB/s</td><td>1.1 MB/s</td><td>0.30 / 0.30 MB/s</td></tr><tr><td><strong>Besu</strong></td><td>5.6 GiB</td><td>9.7 GiB</td><td>0.44 cores</td><td>2.15 cores</td><td>3.0 MB/s</td><td>1.5 MB/s</td><td>0.14 / 0.09 MB/s</td></tr><tr><td><strong>Erigon</strong></td><td>6.0 GiB</td><td>13.6 GiB</td><td>0.45 cores</td><td>2.86 cores</td><td>8.1 MB/s</td><td>22.7 MB/s</td><td>0.24 / 0.24 MB/s</td></tr><tr><td><strong>Geth</strong></td><td>7.9 GiB</td><td>8.4 GiB</td><td>0.48 cores</td><td>1.15 cores</td><td>0.9 MB/s</td><td>0.9 MB/s</td><td>0.33 / 0.68 MB/s</td></tr><tr><td><strong>Reth</strong> (v1.11.3, see note)</td><td>8.5 GiB</td><td>12.7 GiB</td><td>0.42 cores</td><td>0.94 cores</td><td>2.0 MB/s</td><td>4.0 MB/s</td><td>0.36 / 0.52 MB/s</td></tr><tr><td><strong>Ethrex</strong> (64 GiB host)</td><td>15.6 GiB</td><td>17.6 GiB</td><td>0.55 cores</td><td>1.09 cores</td><td>1.0 MB/s</td><td>1.1 MB/s</td><td>0.82 / 0.74 MB/s</td></tr></tbody></table>
<p>RAM is host memory in use (total minus available). Throughput values are decimal MB/s. CPU is in cores of the 12 each host has. P2P traffic is the host's public interface; the internal interface (engine API, monitoring) is excluded. <strong>Reth note:</strong> the version on our hosts during the June window was mid-resync, so Reth is measured over four days ending 2026-04-23, its last fully-synced window on this fleet, running v1.11.3. The chain head was about 0.4M blocks lower then, so read Reth as same-regime, not same-day. More below.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ram-5-to-16-gib-and-one-client-out-of-envelope">RAM: 5 to 16 GiB, and one client out of envelope<a href="https://docs.stereumlabs.com/blog/ethereum-ec-hardware-footprint#ram-5-to-16-gib-and-one-client-out-of-envelope" class="hash-link" aria-label="Direct link to RAM: 5 to 16 GiB, and one client out of envelope" title="Direct link to RAM: 5 to 16 GiB, and one client out of envelope" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Host RAM in use per execution client: averages from 4.9 GiB (Nethermind) to 15.6 GiB (Ethrex), with peaks reaching 13.6 GiB on Erigon and 17.6 GiB on Ethrex" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDY4MCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNjgwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTYiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjgiIGZvbnQtd2VpZ2h0PSI3MDAiPkhvc3QgUkFNIGluIHVzZSBwZXIgZXhlY3V0aW9uIGNsaWVudDwvdGV4dD4KICA8dGV4dCB4PSI0OCIgeT0iODgiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTciPmF2ZXJhZ2UgYW5kIHBlYWssIEdpQiDCtyBvbmUgZGVkaWNhdGVkIGhvc3QgcGVyIEVDLCBhdmVyYWdlZCBhY3Jvc3MgNiBDQyBwYWlyaW5nczwvdGV4dD4KCiAgPCEtLSBwbG90IGFyZWE6IHggMjIwLi4xMTMwIG1hcHMgMC4uMjAgR2lCIDsgMSBHaUIgPSA0NS41cHggOyBncmlkbGluZXMgNC84LzEyLzE2LzIwIC0tPgogIDxnIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIxIj4KICAgIDxsaW5lIHgxPSI0MDIiIHkxPSIxMTYiIHgyPSI0MDIiIHkyPSI1NTYiLz4KICAgIDxsaW5lIHgxPSI1ODQiIHkxPSIxMTYiIHgyPSI1ODQiIHkyPSI1NTYiLz4KICAgIDxsaW5lIHgxPSI3NjYiIHkxPSIxMTYiIHgyPSI3NjYiIHkyPSI1NTYiLz4KICAgIDxsaW5lIHgxPSIxMTMwIiB5MT0iMTE2IiB4Mj0iMTEzMCIgeTI9IjU1NiIvPgogIDwvZz4KICA8bGluZSB4MT0iOTQ4IiB5MT0iMTE2IiB4Mj0iOTQ4IiB5Mj0iNTU2IiBzdHJva2U9IiNmODcxNzEiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWRhc2hhcnJheT0iNyA1Ii8+CiAgPHRleHQgeD0iOTQ4IiB5PSIxMTAiIGZpbGw9IiNmY2E1YTUiIGZvbnQtc2l6ZT0iMTUiIHRleHQtYW5jaG9yPSJtaWRkbGUiPjE2IEdpQiBob3N0IGNlaWxpbmc8L3RleHQ+CiAgPGcgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+CiAgICA8dGV4dCB4PSIyMjAiIHk9IjU3OCI+MDwvdGV4dD4KICAgIDx0ZXh0IHg9IjQwMiIgeT0iNTc4Ij40PC90ZXh0PgogICAgPHRleHQgeD0iNTg0IiB5PSI1NzgiPjg8L3RleHQ+CiAgICA8dGV4dCB4PSI3NjYiIHk9IjU3OCI+MTI8L3RleHQ+CiAgICA8dGV4dCB4PSI5NDgiIHk9IjU3OCI+MTY8L3RleHQ+CiAgICA8dGV4dCB4PSIxMTMwIiB5PSI1NzgiPjIwIEdpQjwvdGV4dD4KICA8L2c+CgogIDwhLS0gTmV0aGVybWluZCBhdmcgNC45IC0+IDIyMywgcGVhayA2LjIgLT4gNTAyIC0tPgogIDxnPgogICAgPHRleHQgeD0iMjAwIiB5PSIxNjEiIGZpbGw9IiNlMmU4ZjQiIGZvbnQtc2l6ZT0iMTciIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI2MDAiPk5ldGhlcm1pbmQ8L3RleHQ+CiAgICA8cmVjdCB4PSIyMjAiIHk9IjE0MCIgd2lkdGg9IjIyMyIgaGVpZ2h0PSIzMCIgcng9IjQiIGZpbGw9IiM3OThiZmYiLz4KICAgIDxsaW5lIHgxPSI1MDIiIHkxPSIxMzQiIHgyPSI1MDIiIHkyPSIxNzYiIHN0cm9rZT0iI2ZkZTY4YSIgc3Ryb2tlLXdpZHRoPSIzIi8+CiAgICA8dGV4dCB4PSI0NTIiIHk9IjE2MSIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNSI+NC45PC90ZXh0PgogICAgPHRleHQgeD0iNTEyIiB5PSIxNjEiIGZpbGw9IiNmZGU2OGEiIGZvbnQtc2l6ZT0iMTQiPnBlYWsgNi4yPC90ZXh0PgogIDwvZz4KICA8IS0tIEJlc3UgYXZnIDUuNiAtPiAyNTUsIHBlYWsgOS43IC0+IDY2MSAtLT4KICA8Zz4KICAgIDx0ZXh0IHg9IjIwMCIgeT0iMjMxIiBmaWxsPSIjZTJlOGY0IiBmb250LXNpemU9IjE3IiB0ZXh0LWFuY2hvcj0iZW5kIiBmb250LXdlaWdodD0iNjAwIj5CZXN1PC90ZXh0PgogICAgPHJlY3QgeD0iMjIwIiB5PSIyMTAiIHdpZHRoPSIyNTUiIGhlaWdodD0iMzAiIHJ4PSI0IiBmaWxsPSIjNzk4YmZmIi8+CiAgICA8bGluZSB4MT0iNjYxIiB5MT0iMjA0IiB4Mj0iNjYxIiB5Mj0iMjQ2IiBzdHJva2U9IiNmZGU2OGEiIHN0cm9rZS13aWR0aD0iMyIvPgogICAgPHRleHQgeD0iNDg0IiB5PSIyMzEiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTUiPjUuNjwvdGV4dD4KICAgIDx0ZXh0IHg9IjY3MSIgeT0iMjMxIiBmaWxsPSIjZmRlNjhhIiBmb250LXNpemU9IjE0Ij5wZWFrIDkuNzwvdGV4dD4KICA8L2c+CiAgPCEtLSBFcmlnb24gYXZnIDYuMCAtPiAyNzMsIHBlYWsgMTMuNiAtPiA4MzkgLS0+CiAgPGc+CiAgICA8dGV4dCB4PSIyMDAiIHk9IjMwMSIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxNyIgdGV4dC1hbmNob3I9ImVuZCIgZm9udC13ZWlnaHQ9IjYwMCI+RXJpZ29uPC90ZXh0PgogICAgPHJlY3QgeD0iMjIwIiB5PSIyODAiIHdpZHRoPSIyNzMiIGhlaWdodD0iMzAiIHJ4PSI0IiBmaWxsPSIjNzk4YmZmIi8+CiAgICA8bGluZSB4MT0iODM5IiB5MT0iMjc0IiB4Mj0iODM5IiB5Mj0iMzE2IiBzdHJva2U9IiNmZGU2OGEiIHN0cm9rZS13aWR0aD0iMyIvPgogICAgPHRleHQgeD0iNTAyIiB5PSIzMDEiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTUiPjYuMDwvdGV4dD4KICAgIDx0ZXh0IHg9Ijg0OSIgeT0iMzAxIiBmaWxsPSIjZmRlNjhhIiBmb250LXNpemU9IjE0Ij5wZWFrIDEzLjY8L3RleHQ+CiAgPC9nPgogIDwhLS0gR2V0aCBhdmcgNy45IC0+IDM1OSwgcGVhayA4LjQgLT4gNjAyIC0tPgogIDxnPgogICAgPHRleHQgeD0iMjAwIiB5PSIzNzEiIGZpbGw9IiNlMmU4ZjQiIGZvbnQtc2l6ZT0iMTciIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI2MDAiPkdldGg8L3RleHQ+CiAgICA8cmVjdCB4PSIyMjAiIHk9IjM1MCIgd2lkdGg9IjM1OSIgaGVpZ2h0PSIzMCIgcng9IjQiIGZpbGw9IiM3OThiZmYiLz4KICAgIDxsaW5lIHgxPSI2MDIiIHkxPSIzNDQiIHgyPSI2MDIiIHkyPSIzODYiIHN0cm9rZT0iI2ZkZTY4YSIgc3Ryb2tlLXdpZHRoPSIzIi8+CiAgICA8dGV4dCB4PSI1NDYiIHk9IjM3MSIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNSI+Ny45PC90ZXh0PgogICAgPHRleHQgeD0iNjEyIiB5PSIzNzEiIGZpbGw9IiNmZGU2OGEiIGZvbnQtc2l6ZT0iMTQiPnBlYWsgOC40PC90ZXh0PgogIDwvZz4KICA8IS0tIFJldGggYXZnIDguNSAtPiAzODcsIHBlYWsgMTIuNyAtPiA3OTggOyB2MS4xMS4zIHN5bmNlZCAtLT4KICA8Zz4KICAgIDx0ZXh0IHg9IjIwMCIgeT0iNDQxIiBmaWxsPSIjZTJlOGY0IiBmb250LXNpemU9IjE3IiB0ZXh0LWFuY2hvcj0iZW5kIiBmb250LXdlaWdodD0iNjAwIj5SZXRoPC90ZXh0PgogICAgPHJlY3QgeD0iMjIwIiB5PSI0MjAiIHdpZHRoPSIzODciIGhlaWdodD0iMzAiIHJ4PSI0IiBmaWxsPSIjNWU2YWQ2Ii8+CiAgICA8bGluZSB4MT0iNzk4IiB5MT0iNDE0IiB4Mj0iNzk4IiB5Mj0iNDU2IiBzdHJva2U9IiNmZGU2OGEiIHN0cm9rZS13aWR0aD0iMyIvPgogICAgPHRleHQgeD0iNTc0IiB5PSI0NDEiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTUiPjguNTwvdGV4dD4KICAgIDx0ZXh0IHg9IjgwOCIgeT0iNDQxIiBmaWxsPSIjZmRlNjhhIiBmb250LXNpemU9IjE0Ij5wZWFrIDEyLjc8L3RleHQ+CiAgICA8dGV4dCB4PSIyMjAiIHk9IjQ3MCIgZmlsbD0iIzhlOWJiZCIgZm9udC1zaXplPSIxMyI+djEuMTEuMywgbGFzdCBzeW5jZWQgd2luZG93IChBcHIgMjAyNik8L3RleHQ+CiAgPC9nPgogIDwhLS0gRXRocmV4IGF2ZyAxNS42IC0+IDcxMCwgcGVhayAxNy42IC0+IDEwMjEgOyA2NCBHaUIgaG9zdCAtLT4KICA8Zz4KICAgIDx0ZXh0IHg9IjIwMCIgeT0iNTExIiBmaWxsPSIjZTJlOGY0IiBmb250LXNpemU9IjE3IiB0ZXh0LWFuY2hvcj0iZW5kIiBmb250LXdlaWdodD0iNjAwIj5FdGhyZXg8L3RleHQ+CiAgICA8cmVjdCB4PSIyMjAiIHk9IjQ5MCIgd2lkdGg9IjcxMCIgaGVpZ2h0PSIzMCIgcng9IjQiIGZpbGw9IiNmOTczMTYiLz4KICAgIDxsaW5lIHgxPSIxMDIxIiB5MT0iNDg0IiB4Mj0iMTAyMSIgeTI9IjUyNiIgc3Ryb2tlPSIjZmRlNjhhIiBzdHJva2Utd2lkdGg9IjMiLz4KICAgIDx0ZXh0IHg9Ijg4MCIgeT0iNTExIiBmaWxsPSIjMGUxNTMwIiBmb250LXNpemU9IjE1IiBmb250LXdlaWdodD0iNzAwIj4xNS42PC90ZXh0PgogICAgPHRleHQgeD0iMTAzMSIgeT0iNTExIiBmaWxsPSIjZmRlNjhhIiBmb250LXNpemU9IjE0Ij5wZWFrIDE3LjY8L3RleHQ+CiAgICA8dGV4dCB4PSIyMjAiIHk9IjU0MCIgZmlsbD0iI2ZiOTIzYyIgZm9udC1zaXplPSIxMyI+cnVucyBvbiBhIDY0IEdpQiBob3N0OiB3b3JraW5nIHNldCBleGNlZWRzIHRoZSAxNiBHaUIgZW52ZWxvcGU8L3RleHQ+CiAgPC9nPgoKICA8dGV4dCB4PSI0OCIgeT0iNjI0IiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjE0Ij5SQU0gaW4gdXNlID0gdG90YWwgbWludXMgYXZhaWxhYmxlIMK3IHBlYWtzIGFyZSB0aGUgaGlnaGVzdCAzMC1taW51dGUgc2FtcGxlIGluIHRoZSB3aW5kb3c8L3RleHQ+CiAgPHRleHQgeD0iNDgiIHk9IjY0OCIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxNCI+Zml2ZSBjbGllbnRzIEp1bmUgMjAyNjsgUmV0aCBmcm9tIGl0cyBsYXN0IHN5bmNlZCB3aW5kb3csIHYxLjExLjMsIEFwcmlsIDIwMjY8L3RleHQ+CiAgPHRleHQgeD0iMTE1MiIgeT0iNjQ4IiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0iZW5kIj5kb2NzLnN0ZXJldW1sYWJzLmNvbTwvdGV4dD4KPC9zdmc+Cg==" width="1200" height="680" class="img_ev3q"></p>
<p>Five of the six fit a 16 GiB host. Nethermind is the lightest at 4.9 GiB average, Geth the steadiest heavyweight at 7.9 GiB with a peak only half a GiB above its average, and Reth sits just above it at 8.5 GiB. The peak column is where sizing decisions live: Besu spikes to 9.7 GiB, Reth to 12.7, and Erigon's commit and prune cycles push the host to 13.6 GiB. On 16 GiB that still works, but those three leave the least slack.</p>
<p>Ethrex does not fit. Its process alone held 15.3 GiB resident, more than the usable RAM of the 16 GiB hosts the other five run on, so its set lives on 64 GiB machines where it averaged 15.6 GiB and peaked at 17.6 GiB. No judgement attached: it is the youngest client of the six and the same fleet measured it executing blocks in 66 ms at the tip. But if you plan an Ethrex node today, plan more than 16 GiB.</p>
<p>The consensus partner barely matters for the established clients: across the six pairings, per-pairing RAM varies by one to four percent for Geth, Nethermind, Besu and Erigon. Ethrex moves more, 15.7 to 19.1 GiB depending on the partner over a 7-day view.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-rss-trap">The RSS trap<a href="https://docs.stereumlabs.com/blog/ethereum-ec-hardware-footprint#the-rss-trap" class="hash-link" aria-label="Direct link to The RSS trap" title="Direct link to The RSS trap" translate="no">​</a></h2>
<p>If you put these six clients on one RSS dashboard, Erigon looks like it is about to die: its process reports 12.9 GiB resident on a host whose memory in use is 6.0 GiB. Both numbers are correct. Erigon (and Reth) serve state from memory-mapped files, and resident set size counts every mapped page currently in RAM, almost all of which the kernel can reclaim on demand. Ethrex's 15.3 GiB RSS, by contrast, sits within a few hundred MiB of its host's missing memory: that allocation is anonymous and cannot be reclaimed.</p>
<p><img decoding="async" loading="lazy" alt="Process RSS versus host memory in use for Besu, Erigon and Ethrex: Erigon reports 12.9 GiB RSS on a host using 6.0 GiB, while Ethrex&amp;#39;s 15.3 GiB RSS matches its host&amp;#39;s 15.6 GiB" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDYyMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNjIwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTYiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjgiIGZvbnQtd2VpZ2h0PSI3MDAiPlNhbWUgbWV0cmljLCBvcHBvc2l0ZSBtZWFuaW5nczwvdGV4dD4KICA8dGV4dCB4PSI0OCIgeT0iODgiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTciPnByb2Nlc3MgUlNTIHZzIGhvc3QgbWVtb3J5IGluIHVzZSwgR2lCIMK3IHRoZSB0aHJlZSBjbGllbnRzIHRoYXQgZXhwb3NlIHByb2Nlc3MgUlNTIMK3IDIwMjYtMDYtMTE8L3RleHQ+CgogIDwhLS0gbGVnZW5kIC0tPgogIDxyZWN0IHg9IjgzMCIgeT0iNDQiIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgcng9IjMiIGZpbGw9IiNjMDg0ZmMiLz4KICA8dGV4dCB4PSI4NTYiIHk9IjU4IiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE1Ij5wcm9jZXNzIFJTUzwvdGV4dD4KICA8cmVjdCB4PSI5OTAiIHk9IjQ0IiB3aWR0aD0iMTgiIGhlaWdodD0iMTgiIHJ4PSIzIiBmaWxsPSIjMmRkNGJmIi8+CiAgPHRleHQgeD0iMTAxNiIgeT0iNTgiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTUiPmhvc3QgbWVtb3J5IGluIHVzZTwvdGV4dD4KCiAgPCEtLSBwbG90IGFyZWE6IHggMjIwLi4xMTMwIG1hcHMgMC4uMTYgR2lCIDsgMSBHaUIgPSA1Ni44NzUgcHggLS0+CiAgPGcgc3Ryb2tlPSIjMWMyNjU0IiBzdHJva2Utd2lkdGg9IjEiPgogICAgPGxpbmUgeDE9IjQ0OCIgeTE9IjExNiIgeDI9IjQ0OCIgeTI9IjUyMCIvPgogICAgPGxpbmUgeDE9IjY3NSIgeTE9IjExNiIgeDI9IjY3NSIgeTI9IjUyMCIvPgogICAgPGxpbmUgeDE9IjkwMyIgeTE9IjExNiIgeDI9IjkwMyIgeTI9IjUyMCIvPgogICAgPGxpbmUgeDE9IjExMzAiIHkxPSIxMTYiIHgyPSIxMTMwIiB5Mj0iNTIwIi8+CiAgPC9nPgogIDxnIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJtaWRkbGUiPgogICAgPHRleHQgeD0iMjIwIiB5PSI1NDIiPjA8L3RleHQ+CiAgICA8dGV4dCB4PSI0NDgiIHk9IjU0MiI+NDwvdGV4dD4KICAgIDx0ZXh0IHg9IjY3NSIgeT0iNTQyIj44PC90ZXh0PgogICAgPHRleHQgeD0iOTAzIiB5PSI1NDIiPjEyPC90ZXh0PgogICAgPHRleHQgeD0iMTEzMCIgeT0iNTQyIj4xNiBHaUI8L3RleHQ+CiAgPC9nPgoKICA8IS0tIEJlc3U6IFJTUyA0LjYgLT4gMjYyLCB1c2VkIDUuNiAtPiAzMTkgLS0+CiAgPGc+CiAgICA8dGV4dCB4PSIyMDAiIHk9IjE2OCIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxNyIgdGV4dC1hbmNob3I9ImVuZCIgZm9udC13ZWlnaHQ9IjYwMCI+QmVzdTwvdGV4dD4KICAgIDxyZWN0IHg9IjIyMCIgeT0iMTM2IiB3aWR0aD0iMjYyIiBoZWlnaHQ9IjIwIiByeD0iMyIgZmlsbD0iI2MwODRmYyIvPgogICAgPHJlY3QgeD0iMjIwIiB5PSIxNjAiIHdpZHRoPSIzMTkiIGhlaWdodD0iMjAiIHJ4PSIzIiBmaWxsPSIjMmRkNGJmIi8+CiAgICA8dGV4dCB4PSI0OTAiIHk9IjE1MSIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCI+NC42PC90ZXh0PgogICAgPHRleHQgeD0iNTQ3IiB5PSIxNzUiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTQiPjUuNjwvdGV4dD4KICAgIDx0ZXh0IHg9IjIyMCIgeT0iMjA0IiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjE0Ij5KVk0gcHJvY2VzcyBiZWxvdyBob3N0IHVzZTogdGhlIGRpZmZlcmVuY2UgaXMgT1MgYW5kIGV4cG9ydGVyczwvdGV4dD4KICA8L2c+CgogIDwhLS0gRXJpZ29uOiBSU1MgMTIuOSAtPiA3MzQsIHVzZWQgNi4wIC0+IDM0MSAtLT4KICA8Zz4KICAgIDx0ZXh0IHg9IjIwMCIgeT0iMjc4IiBmaWxsPSIjZTJlOGY0IiBmb250LXNpemU9IjE3IiB0ZXh0LWFuY2hvcj0iZW5kIiBmb250LXdlaWdodD0iNjAwIj5Fcmlnb248L3RleHQ+CiAgICA8cmVjdCB4PSIyMjAiIHk9IjI0NiIgd2lkdGg9IjczNCIgaGVpZ2h0PSIyMCIgcng9IjMiIGZpbGw9IiNjMDg0ZmMiLz4KICAgIDxyZWN0IHg9IjIyMCIgeT0iMjcwIiB3aWR0aD0iMzQxIiBoZWlnaHQ9IjIwIiByeD0iMyIgZmlsbD0iIzJkZDRiZiIvPgogICAgPHRleHQgeD0iOTYyIiB5PSIyNjEiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTQiPjEyLjk8L3RleHQ+CiAgICA8dGV4dCB4PSI1NjkiIHk9IjI4NSIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCI+Ni4wPC90ZXh0PgogICAgPHRleHQgeD0iMjIwIiB5PSIzMTQiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTQiPlJTUyBjb3VudHMgbWVtb3J5LW1hcHBlZCBwYWdlcyB0aGUga2VybmVsIGNhbiByZWNsYWltIGF0IGFueSB0aW1lOiBsb29rcyBjcml0aWNhbCwgaXMgbm90PC90ZXh0PgogIDwvZz4KCiAgPCEtLSBFdGhyZXg6IFJTUyAxNS4zIC0+IDg3MCwgdXNlZCAxNS42IC0+IDg4NyAtLT4KICA8Zz4KICAgIDx0ZXh0IHg9IjIwMCIgeT0iMzg4IiBmaWxsPSIjZTJlOGY0IiBmb250LXNpemU9IjE3IiB0ZXh0LWFuY2hvcj0iZW5kIiBmb250LXdlaWdodD0iNjAwIj5FdGhyZXg8L3RleHQ+CiAgICA8cmVjdCB4PSIyMjAiIHk9IjM1NiIgd2lkdGg9Ijg3MCIgaGVpZ2h0PSIyMCIgcng9IjMiIGZpbGw9IiNjMDg0ZmMiLz4KICAgIDxyZWN0IHg9IjIyMCIgeT0iMzgwIiB3aWR0aD0iODg3IiBoZWlnaHQ9IjIwIiByeD0iMyIgZmlsbD0iIzJkZDRiZiIvPgogICAgPHRleHQgeD0iMTA5OCIgeT0iMzcxIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0Ij4xNS4zPC90ZXh0PgogICAgPHRleHQgeD0iMTA1NiIgeT0iMzk1IiBmaWxsPSIjMGUxNTMwIiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iNzAwIj4xNS42PC90ZXh0PgogICAgPHRleHQgeD0iMjIwIiB5PSI0MjQiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTQiPmFub255bW91cyBtZW1vcnksIG5vdGhpbmcgdG8gcmVjbGFpbTogaGVyZSB0aGUgdHdvIG51bWJlcnMgYWdyZWUsIGFuZCBib3RoIG1lYW4gaXQ8L3RleHQ+CiAgPC9nPgoKICA8dGV4dCB4PSI0OCIgeT0iNDcwIiBmaWxsPSIjOGU5YmJkIiBmb250LXNpemU9IjE0IiBmb250LXN0eWxlPSJpdGFsaWMiPkdldGgsIE5ldGhlcm1pbmQgYW5kIFJldGggcHVibGlzaCBydW50aW1lIG9yIGFsbG9jYXRvciB2aWV3cyBpbnN0ZWFkIG9mIHByb2Nlc3MgUlNTLCBhIGdhcCBvZiBpdHMgb3duLjwvdGV4dD4KCiAgPHRleHQgeD0iNDgiIHk9IjU4NCIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxNCI+aG9zdCBtZW1vcnkgaW4gdXNlID0gdG90YWwgbWludXMgYXZhaWxhYmxlIMK3IGFsZXJ0IG9uIHRoaXMgb25lPC90ZXh0PgogIDx0ZXh0IHg9IjExNTIiIHk9IjU4NCIgZmlsbD0iIzdjODlhOCIgZm9udC1zaXplPSIxNCIgdGV4dC1hbmNob3I9ImVuZCI+ZG9jcy5zdGVyZXVtbGFicy5jb208L3RleHQ+Cjwvc3ZnPgo=" width="1200" height="620" class="img_ev3q"></p>
<p>Same metric name, opposite meanings. Alert on host available memory, not on the client process RSS, or an mmap-based client will page you forever while a genuinely full host stays quiet. The rest of each 16 GiB box fills with page cache (7 to 10 GiB here), which is the system working as intended, not a leak. We hit the same class of problem with disk metrics in <a class="" href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour">the pruning census</a> and with a heap that did lie in <a class="" href="https://docs.stereumlabs.com/blog/besu-bonsai-layered-storage-memory-leak">the Besu case study</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="cpu-half-a-core-at-the-tip">CPU: half a core at the tip<a href="https://docs.stereumlabs.com/blog/ethereum-ec-hardware-footprint#cpu-half-a-core-at-the-tip" class="hash-link" aria-label="Direct link to CPU: half a core at the tip" title="Direct link to CPU: half a core at the tip" translate="no">​</a></h2>
<p>Every synced client averaged between 0.42 and 0.55 of one core. Twelve cores sit mostly idle once a node follows the chain; the busiest half-hour of any client was Erigon's 2.86 cores. CPU is a sync-time resource, and Reth shows both sides of it: 0.42 cores synced, against the 1.22 cores its hosts pull right now while they resync the chain. If you size a machine for an execution client, you buy cores for the initial sync and for recovery after downtime, not for steady state. <a class="" href="https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026">Our sync-speed census</a> measures that phase client by client.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="disk-io-where-the-spread-gets-serious">Disk I/O: where the spread gets serious<a href="https://docs.stereumlabs.com/blog/ethereum-ec-hardware-footprint#disk-io-where-the-spread-gets-serious" class="hash-link" aria-label="Direct link to Disk I/O: where the spread gets serious" title="Direct link to Disk I/O: where the spread gets serious" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Disk throughput per execution client: writes from 0.9 MB/s (Geth) to 22.7 MB/s (Erigon), reads from 0.9 to 8.1 MB/s among synced clients" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDcwMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPHJlY3Qgd2lkdGg9IjEyMDAiIGhlaWdodD0iNzAwIiByeD0iMTIiIGZpbGw9IiMwZTE1MzAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTYiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjgiIGZvbnQtd2VpZ2h0PSI3MDAiPkRpc2sgdGhyb3VnaHB1dCBwZXIgZXhlY3V0aW9uIGNsaWVudDwvdGV4dD4KICA8dGV4dCB4PSI0OCIgeT0iODgiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTciPmF2ZXJhZ2UsIE1CL3Mgwrcgc2FtZSBob3N0cywgc2FtZSBjaGFpbiDCtyBvcmRlcmVkIGJ5IHdyaXRlIHJhdGU8L3RleHQ+CgogIDwhLS0gbGVnZW5kIC0tPgogIDxyZWN0IHg9IjkwMCIgeT0iNDQiIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgcng9IjMiIGZpbGw9IiMzOGJkZjgiLz4KICA8dGV4dCB4PSI5MjYiIHk9IjU4IiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE1Ij5yZWFkPC90ZXh0PgogIDxyZWN0IHg9Ijk5MCIgeT0iNDQiIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgcng9IjMiIGZpbGw9IiNmOTczMTYiLz4KICA8dGV4dCB4PSIxMDE2IiB5PSI1OCIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNSI+d3JpdGU8L3RleHQ+CgogIDwhLS0gcGxvdCBhcmVhOiB4IDIyMC4uMTEzMCBtYXBzIDAuLjI1IE1CL3MgOyAxIE1CL3MgPSAzNi40IHB4IC0tPgogIDxnIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIxIj4KICAgIDxsaW5lIHgxPSI0MDIiIHkxPSIxMTYiIHgyPSI0MDIiIHkyPSI2MTIiLz4KICAgIDxsaW5lIHgxPSI1ODQiIHkxPSIxMTYiIHgyPSI1ODQiIHkyPSI2MTIiLz4KICAgIDxsaW5lIHgxPSI3NjYiIHkxPSIxMTYiIHgyPSI3NjYiIHkyPSI2MTIiLz4KICAgIDxsaW5lIHgxPSI5NDgiIHkxPSIxMTYiIHgyPSI5NDgiIHkyPSI2MTIiLz4KICAgIDxsaW5lIHgxPSIxMTMwIiB5MT0iMTE2IiB4Mj0iMTEzMCIgeTI9IjYxMiIvPgogIDwvZz4KICA8ZyBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj4KICAgIDx0ZXh0IHg9IjIyMCIgeT0iNjM0Ij4wPC90ZXh0PgogICAgPHRleHQgeD0iNDAyIiB5PSI2MzQiPjU8L3RleHQ+CiAgICA8dGV4dCB4PSI1ODQiIHk9IjYzNCI+MTA8L3RleHQ+CiAgICA8dGV4dCB4PSI3NjYiIHk9IjYzNCI+MTU8L3RleHQ+CiAgICA8dGV4dCB4PSI5NDgiIHk9IjYzNCI+MjA8L3RleHQ+CiAgICA8dGV4dCB4PSIxMTMwIiB5PSI2MzQiPjI1IE1CL3M8L3RleHQ+CiAgPC9nPgoKICA8IS0tIEdldGggciAwLjkgLT4gMzMsIHcgMC45IC0+IDMzIC0tPgogIDxnPgogICAgPHRleHQgeD0iMjAwIiB5PSIxNTYiIGZpbGw9IiNlMmU4ZjQiIGZvbnQtc2l6ZT0iMTciIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI2MDAiPkdldGg8L3RleHQ+CiAgICA8cmVjdCB4PSIyMjAiIHk9IjEzNCIgd2lkdGg9IjMzIiBoZWlnaHQ9IjE4IiByeD0iMyIgZmlsbD0iIzM4YmRmOCIvPgogICAgPHJlY3QgeD0iMjIwIiB5PSIxNTYiIHdpZHRoPSIzMyIgaGVpZ2h0PSIxOCIgcng9IjMiIGZpbGw9IiNmOTczMTYiLz4KICAgIDx0ZXh0IHg9IjI2MSIgeT0iMTQ5IiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0Ij4wLjk8L3RleHQ+CiAgICA8dGV4dCB4PSIyNjEiIHk9IjE3MSIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCI+MC45PC90ZXh0PgogIDwvZz4KICA8IS0tIE5ldGhlcm1pbmQgciAxLjQgLT4gNTEsIHcgMS4xIC0+IDQwIC0tPgogIDxnPgogICAgPHRleHQgeD0iMjAwIiB5PSIyMzQiIGZpbGw9IiNlMmU4ZjQiIGZvbnQtc2l6ZT0iMTciIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI2MDAiPk5ldGhlcm1pbmQ8L3RleHQ+CiAgICA8cmVjdCB4PSIyMjAiIHk9IjIxMiIgd2lkdGg9IjUxIiBoZWlnaHQ9IjE4IiByeD0iMyIgZmlsbD0iIzM4YmRmOCIvPgogICAgPHJlY3QgeD0iMjIwIiB5PSIyMzQiIHdpZHRoPSI0MCIgaGVpZ2h0PSIxOCIgcng9IjMiIGZpbGw9IiNmOTczMTYiLz4KICAgIDx0ZXh0IHg9IjI3OSIgeT0iMjI3IiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0Ij4xLjQ8L3RleHQ+CiAgICA8dGV4dCB4PSIyNjgiIHk9IjI0OSIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCI+MS4xPC90ZXh0PgogIDwvZz4KICA8IS0tIEV0aHJleCByIDEuMCAtPiAzNiwgdyAxLjEgLT4gNDAgLS0+CiAgPGc+CiAgICA8dGV4dCB4PSIyMDAiIHk9IjMxMiIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxNyIgdGV4dC1hbmNob3I9ImVuZCIgZm9udC13ZWlnaHQ9IjYwMCI+RXRocmV4PC90ZXh0PgogICAgPHJlY3QgeD0iMjIwIiB5PSIyOTAiIHdpZHRoPSIzNiIgaGVpZ2h0PSIxOCIgcng9IjMiIGZpbGw9IiMzOGJkZjgiLz4KICAgIDxyZWN0IHg9IjIyMCIgeT0iMzEyIiB3aWR0aD0iNDAiIGhlaWdodD0iMTgiIHJ4PSIzIiBmaWxsPSIjZjk3MzE2Ii8+CiAgICA8dGV4dCB4PSIyNjQiIHk9IjMwNSIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCI+MS4wPC90ZXh0PgogICAgPHRleHQgeD0iMjY4IiB5PSIzMjciIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTQiPjEuMTwvdGV4dD4KICA8L2c+CiAgPCEtLSBCZXN1IHIgMy4wIC0+IDEwOSwgdyAxLjUgLT4gNTUgLS0+CiAgPGc+CiAgICA8dGV4dCB4PSIyMDAiIHk9IjM5MCIgZmlsbD0iI2UyZThmNCIgZm9udC1zaXplPSIxNyIgdGV4dC1hbmNob3I9ImVuZCIgZm9udC13ZWlnaHQ9IjYwMCI+QmVzdTwvdGV4dD4KICAgIDxyZWN0IHg9IjIyMCIgeT0iMzY4IiB3aWR0aD0iMTA5IiBoZWlnaHQ9IjE4IiByeD0iMyIgZmlsbD0iIzM4YmRmOCIvPgogICAgPHJlY3QgeD0iMjIwIiB5PSIzOTAiIHdpZHRoPSI1NSIgaGVpZ2h0PSIxOCIgcng9IjMiIGZpbGw9IiNmOTczMTYiLz4KICAgIDx0ZXh0IHg9IjMzNyIgeT0iMzgzIiBmaWxsPSIjY2RkNmY0IiBmb250LXNpemU9IjE0Ij4zLjA8L3RleHQ+CiAgICA8dGV4dCB4PSIyODMiIHk9IjQwNSIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCI+MS41PC90ZXh0PgogIDwvZz4KICA8IS0tIFJldGggciAyLjAgLT4gNzMsIHcgNC4wIC0+IDE0NiA7IHYxLjExLjMgc3luY2VkIC0tPgogIDxnPgogICAgPHRleHQgeD0iMjAwIiB5PSI0NjgiIGZpbGw9IiNlMmU4ZjQiIGZvbnQtc2l6ZT0iMTciIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI2MDAiPlJldGg8L3RleHQ+CiAgICA8cmVjdCB4PSIyMjAiIHk9IjQ0NiIgd2lkdGg9IjczIiBoZWlnaHQ9IjE4IiByeD0iMyIgZmlsbD0iIzM4YmRmOCIvPgogICAgPHJlY3QgeD0iMjIwIiB5PSI0NjgiIHdpZHRoPSIxNDYiIGhlaWdodD0iMTgiIHJ4PSIzIiBmaWxsPSIjZjk3MzE2Ii8+CiAgICA8dGV4dCB4PSIzMDEiIHk9IjQ2MSIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCI+Mi4wPC90ZXh0PgogICAgPHRleHQgeD0iMzc0IiB5PSI0ODMiIGZpbGw9IiNjZGQ2ZjQiIGZvbnQtc2l6ZT0iMTQiPjQuMDwvdGV4dD4KICAgIDx0ZXh0IHg9IjQzMCIgeT0iNDY4IiBmaWxsPSIjOGU5YmJkIiBmb250LXNpemU9IjEzIj52MS4xMS4zLCBsYXN0IHN5bmNlZCB3aW5kb3cgKEFwciAyMDI2KTwvdGV4dD4KICA8L2c+CiAgPCEtLSBFcmlnb24gciA4LjEgLT4gMjk1LCB3IDIyLjcgLT4gODI2IC0tPgogIDxnPgogICAgPHRleHQgeD0iMjAwIiB5PSI1NDYiIGZpbGw9IiNlMmU4ZjQiIGZvbnQtc2l6ZT0iMTciIHRleHQtYW5jaG9yPSJlbmQiIGZvbnQtd2VpZ2h0PSI2MDAiPkVyaWdvbjwvdGV4dD4KICAgIDxyZWN0IHg9IjIyMCIgeT0iNTI0IiB3aWR0aD0iMjk1IiBoZWlnaHQ9IjE4IiByeD0iMyIgZmlsbD0iIzM4YmRmOCIvPgogICAgPHJlY3QgeD0iMjIwIiB5PSI1NDYiIHdpZHRoPSI4MjYiIGhlaWdodD0iMTgiIHJ4PSIzIiBmaWxsPSIjZjk3MzE2Ii8+CiAgICA8dGV4dCB4PSI1MjMiIHk9IjUzOSIgZmlsbD0iI2NkZDZmNCIgZm9udC1zaXplPSIxNCI+OC4xPC90ZXh0PgogICAgPHRleHQgeD0iMTAzOCIgeT0iNTYwIiBmaWxsPSIjMGUxNTMwIiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iNzAwIiB0ZXh0LWFuY2hvcj0iZW5kIj4yMi43IE1CL3Mg4omIIDEuOSBUQi9kYXk8L3RleHQ+CiAgPC9nPgoKICA8dGV4dCB4PSI0OCIgeT0iNjYyIiBmaWxsPSIjN2M4OWE4IiBmb250LXNpemU9IjE0Ij5kYXRhIGRldmljZSBvbmx5IMK3IEVyaWdvbiB0cmFkZXMgdGhlIHNtYWxsZXN0IGRpc2sgZm9vdHByaW50ICg1MTkgR0IpIGZvciB0aGUgaGlnaGVzdCBzdXN0YWluZWQgd3JpdGVzPC90ZXh0PgogIDx0ZXh0IHg9IjQ4IiB5PSI2ODQiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTQiPlJldGggZnJvbSBpdHMgc3luY2VkIHYxLjExLjMgd2luZG93OyBpdHMgY3VycmVudCByZXN5bmMgc3VzdGFpbnMgfjIzIE1CL3MsIG9mZiB0aGUgY2hhcnQgaGVyZTwvdGV4dD4KICA8dGV4dCB4PSIxMTUyIiB5PSI2ODQiIGZpbGw9IiM3Yzg5YTgiIGZvbnQtc2l6ZT0iMTQiIHRleHQtYW5jaG9yPSJlbmQiPmRvY3Muc3RlcmV1bWxhYnMuY29tPC90ZXh0Pgo8L3N2Zz4K" width="1200" height="700" class="img_ev3q"></p>
<p>This is the widest spread in the census, and it is architectural. Geth keeps its working state in those 7.9 GiB of RAM and touches disk at under 1 MB/s in each direction, the quietest profile of the six. Nethermind, Besu, Ethrex and Reth stay in the low single digits (Reth at 2.0 read, 4.0 write). Erigon inverts the picture: its layered domain files and continuous background pruning write a sustained <strong>22.7 MB/s, about 1.9 TB per day</strong>, plus 8 MB/s of reads, in exchange for the smallest disk footprint of the fleet (519 GB vs Geth's 1,731 GB).</p>
<p>That write rate is a budget item. A consumer 2 TB NVMe rated for 1,200 TBW reaches its endurance rating in roughly 20 months of Erigon steady state, before counting the initial sync. Enterprise drives shrug at it, but on hobbyist hardware the cheapest-disk client is also the one that consumes disks fastest. Disk capacity itself is the other axis, and we covered it in depth in <a class="" href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour">the pruning post</a>; current footprints run Erigon 519 GB, Ethrex 588 GB, Nethermind 1,222 GB, Besu 1,265 GB and Geth 1,731 GB, with synced Reth (v1.11.3, April) around 1,399 GB.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="network-a-home-connection-is-plenty">Network: a home connection is plenty<a href="https://docs.stereumlabs.com/blog/ethereum-ec-hardware-footprint#network-a-home-connection-is-plenty" class="hash-link" aria-label="Direct link to Network: a home connection is plenty" title="Direct link to Network: a home connection is plenty" translate="no">​</a></h2>
<p>P2P traffic, measured at the host's public interface, stays under 2 MB/s combined for every client. Ethrex moves the most (0.82 MB/s down, 0.74 up, about 4 TB per month both directions combined), Geth uploads the most of the rest (0.68 MB/s, serving peers from its long-lived position in the network), Besu is the quietest at about 0.6 TB per month, with Reth's April figures landing in the middle near 2 TB. On an uncapped line none of this matters; on a metered connection the gap between 0.6 and 4 TB per month picks your client for you. Two notes on reading these numbers: the interface sees discovery chatter, transport overhead and peers that never complete a handshake, so it reads higher than a client's own P2P accounting (Geth's internal counters claim roughly half of what its interface carries), and how each client builds the peer set behind this traffic is covered in <a class="" href="https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis">the peering deep dive</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="reth-and-why-its-row-is-dated-differently">Reth, and why its row is dated differently<a href="https://docs.stereumlabs.com/blog/ethereum-ec-hardware-footprint#reth-and-why-its-row-is-dated-differently" class="hash-link" aria-label="Direct link to Reth, and why its row is dated differently" title="Direct link to Reth, and why its row is dated differently" translate="no">​</a></h2>
<p>Reth's row needs the asterisk because the version on our hosts during the June window was not following the tip. It has been resyncing across two releases (v2.1.0, then v2.2.0) since late April, and another deploy lands today, which resets the back-fill again. So rather than print back-fill load as if it were steady state, we took Reth's numbers from the last window it was demonstrably synced: four days ending 2026-04-23, on v1.11.3, with <code>forkchoiceUpdated</code> answered <code>VALID</code> and the pipeline's finish stage tracking the head block for block. Whether the v2.x line stays behind because of the client or our own deploy cadence is a separate question we have not closed, so we make no claim about it here.</p>
<p>Synced, Reth is unremarkable in the best way: 8.5 GiB average RAM, half a core, 2 MB/s of reads and 4 of writes. That is close to Geth on memory and well under Erigon on disk, which corrects something we expected going in, that Reth's mmap-heavy design would write like Erigon. It does not.</p>
<p>The current back-fill is also a clean illustration of two things this series keeps returning to. First, the cost of syncing: the same hosts that sip 0.42 cores when synced pull 1.22 cores and sustain 22 MB/s reads and 23 MB/s writes while catching up. Second, why we read logs and not just dashboards. Checking the resync this week, Reth's stage checkpoints had all jumped to <code>25236949</code> and a metrics panel would have called it done, but the logs showed only execution, hashing and merkle finished, with the final transaction-lookup and history-index stages still grinding at <code>checkpoint=0</code>, about 93,000 blocks behind the tip, every live payload answered <code>SYNCING</code>. We will refresh all six clients on a single window once the new Reth follows the tip again.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="sizing-takeaways">Sizing takeaways<a href="https://docs.stereumlabs.com/blog/ethereum-ec-hardware-footprint#sizing-takeaways" class="hash-link" aria-label="Direct link to Sizing takeaways" title="Direct link to Sizing takeaways" translate="no">​</a></h2>
<p>Condensed into hardware requirements for a mainnet execution client in mid-2026:</p>
<ul>
<li class=""><strong>16 GiB RAM fits five of six clients</strong> with room to spare; Nethermind and Besu leave the most headroom, Erigon the least. Ethrex currently needs more.</li>
<li class=""><strong>Cores are for syncing.</strong> Half a core follows mainnet; buy 8+ for the day you resync.</li>
<li class=""><strong>Watch TBW, not just GB.</strong> Erigon saves you a terabyte of capacity and spends your drive's write endurance for it. Geth does the opposite.</li>
<li class=""><strong>Bandwidth is a non-issue</strong> unless your line is metered; then 0.6 to 4 TB per month separates the clients.</li>
<li class=""><strong>Alert on host available memory.</strong> Process RSS lies for mmap-based clients.</li>
</ul>
<p>That table at the top is what StereumLabs AI works with on our fleet: identical hosts, one variable, every client pairing observed the same way. This post shows that comparison under the conditions the fleet happened to be in, which is not fully like-for-like: Reth's row comes from an earlier window and the hosts were freshly rebuilt. Lining the clients up on truly equal footing means choosing comparable periods out of a history with uneven data quality and consistency, which is an analysis in its own right, not a lookup on a static panel. That is what StereumLabs AI is built for, and it is how we pinned Reth's last synced window for this post. When one node stops matching its siblings, that divergence is a finding, sometimes <a class="" href="https://docs.stereumlabs.com/blog/besu-bonsai-layered-storage-memory-leak">an upstream bug report</a>. If you run Ethereum infrastructure and want this lens on your own nodes, reach us at <a href="https://stereumlabs.com/" target="_blank" rel="noopener noreferrer" class="">stereumlabs.com</a> or <a href="mailto:contact@stereumlabs.com" target="_blank" rel="noopener noreferrer" class="">contact@stereumlabs.com</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="methodology">Methodology<a href="https://docs.stereumlabs.com/blog/ethereum-ec-hardware-footprint#methodology" class="hash-link" aria-label="Direct link to Methodology" title="Direct link to Methodology" translate="no">​</a></h2>
<p>Numbers come from node_exporter on the dedicated EC hosts of our NDC2 deployment (Vienna), queried on the <code>Prometheus-cold</code> datasource (uid <code>aez9ck4wz05q8e</code>), with the fleet labels documented in <a class="" href="https://docs.stereumlabs.com/docs/dashboards/build-your-own">build your own dashboards</a>. Per-client values average the six CC pairings (<code>avg by (ec_client)</code>); a second Geth set on GCP was excluded as a different platform.</p>
<ul>
<li class=""><strong>Window:</strong> 36 hours ending 2026-06-11 ~15:00 UTC, e.g. <code>avg_over_time((node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes)[36h:30m])</code>. We chose 36 h over our usual 7 d because most EC hosts were rebooted 2.2 days earlier; counter resets at the reboot depress 7-day <code>increase()</code> figures (Erigon's write rate reads 12 MB/s over 7 d but holds 19 to 23 MB/s in every post-reboot hour).</li>
<li class=""><strong>Reth's window:</strong> four days ending 2026-04-23, the last period Reth was synced on this fleet (v1.11.3), measured the same way and averaged across the same six pairings. Confirmed synced by <code>forkchoiceUpdated</code> answered <code>VALID</code> with zero <code>SYNCING</code> and the pipeline finish stage advancing one block per slot; the v2.1.0 then v2.2.0 line deployed since has answered <code>SYNCING</code> continuously. Chain head was ~24.94M then against ~25.29M for the June five.</li>
<li class=""><strong>RAM</strong> is <code>MemTotal - MemAvailable</code> in GiB; peaks are <code>max_over_time</code> over the same window. Process RSS via <code>process_resident_memory_bytes</code> where clients expose it (Besu, Ethrex, Erigon).</li>
<li class=""><strong>CPU</strong> from <code>increase(node_cpu_seconds_total{mode!="idle"}[36h])</code> per host; the busiest-half-hour figure is the max of 30-minute rates.</li>
<li class=""><strong>Disk</strong> from <code>node_disk_read_bytes_total</code> / <code>node_disk_written_bytes_total</code> on the data device. <strong>Network</strong> from <code>node_network_*_bytes_total</code> on the host's public P2P interface only; each host's second, internal interface (engine API from the CC host, Prometheus scrapes, log shipping) is excluded. We cross-checked the interface assignment against Geth's and Nethermind's own P2P byte counters: the host interface reads higher than client-internal accounting because discovery, failed handshakes and transport overhead never reach the client's counter, and we report the host number because it is what your line carries. Binary byte values converted to decimal MB/s.</li>
<li class=""><strong>Hardware:</strong> every EC host has 12 cores; 16 GiB RAM except the Ethrex set (64 GiB). Consensus clients (supernodes) run on separate hosts and are not part of these numbers.</li>
<li class=""><strong>Sync verification</strong> per client from container logs at measurement time (import lines at the live tip for Geth, Besu, Erigon, Ethrex; Nethermind additionally via its own head metric at block 25,294,914; Reth's April window as above). Metrics alone can read "synced" while a client back-fills, which is what Reth's June resync showed and why we check logs; see <a class="" href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour">the pruning post</a> for the long version.</li>
</ul>]]></content:encoded>
            <category>client comparison</category>
            <category>resources</category>
            <category>memory</category>
            <category>storage</category>
            <category>networking</category>
            <category>Geth</category>
            <category>Nethermind</category>
            <category>Besu</category>
            <category>Erigon</category>
            <category>Reth</category>
            <category>Ethrex</category>
        </item>
        <item>
            <title><![CDATA[Tracing a Besu memory leak to a one-line method]]></title>
            <link>https://docs.stereumlabs.com/blog/besu-bonsai-layered-storage-memory-leak</link>
            <guid>https://docs.stereumlabs.com/blog/besu-bonsai-layered-storage-memory-leak</guid>
            <pubDate>Wed, 10 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[How StereumLabs AI traced a Besu Bonsai layered-storage memory leak from one anomalous fleet node, and how a devnet reproduction reopened the upstream issue.]]></description>
            <content:encoded><![CDATA[<p>Six Besu nodes, same version, same hardware, same config. Five held a flat JVM heap around 1.0 to 1.3 GB. The sixth climbed about 10 GB a day and was on track to be OOM-killed roughly 30 hours after a restart. The one thing different about it was the consensus client on the other side of the engine API.</p>
<p>This is a walkthrough of how StereumLabs AI, reading our fleet's metrics and logs, took that one anomalous node, traced it to a single method, and filed it upstream. Besu shipped a round of mitigations and closed the issue. A later devnet reproduction showed the underlying layers still pile up, the issue was reopened, and the fix that followed is now in review. The bug is operational: recoverable by a restart, no consensus impact, no double-sign, no state-root divergence. It is also the kind of cross-client interaction a single-node test will never surface, because it only appears when a live pairing lands in a specific state.</p>
<p><img decoding="async" loading="lazy" alt="Six identical Besu nodes over time: five hold a flat JVM heap near 1 GB while the Prysm-paired node climbs about 10 GB per day toward an out-of-memory kill" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNjAwIDkwMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPGRlZnM+CiAgICA8cGF0dGVybiBpZD0iZ3JpZC10YiIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBwYXR0ZXJuVW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHBhdGggZD0iTSA4MCAwIEwgMCAwIDAgODAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIwLjUiLz4KICAgIDwvcGF0dGVybj4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZC1sZWFrLXRiIiB4MT0iMCUiIHkxPSIxMDAlIiB4Mj0iMTAwJSIgeTI9IjAlIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2I5MWMxYyIvPgogICAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmOTczMTYiLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgPC9kZWZzPgoKICA8cmVjdCB3aWR0aD0iMTYwMCIgaGVpZ2h0PSI5MDAiIGZpbGw9IiMwZTE1MzAiLz4KICA8cmVjdCB3aWR0aD0iMTYwMCIgaGVpZ2h0PSI5MDAiIGZpbGw9InVybCgjZ3JpZC10YikiLz4KICA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTYwMCIgaGVpZ2h0PSIxNCIgZmlsbD0iIzUwNDZlNSIvPgoKICA8dGV4dCB4PSIxMDAiIHk9IjEwMCIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIyOCIgZm9udC13ZWlnaHQ9IjYwMCI+U3RlcmV1bUxhYnM8L3RleHQ+CiAgPHRleHQgeD0iMTUwMCIgeT0iMTAwIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjIwIiB0ZXh0LWFuY2hvcj0iZW5kIj5CZXN1ICMxMDQ5OCDCtyBjYXNlIHN0dWR5PC90ZXh0PgoKICA8dGV4dCB4PSI4MDAiIHk9IjIxMCIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSI1OCIgZm9udC13ZWlnaHQ9IjcwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgbGV0dGVyLXNwYWNpbmc9Ii0xLjUiPlRyYWNpbmcgYSBCZXN1IG1lbW9yeSBsZWFrPC90ZXh0PgogIDx0ZXh0IHg9IjgwMCIgeT0iMjc2IiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjU4IiBmb250LXdlaWdodD0iNzAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBsZXR0ZXItc3BhY2luZz0iLTEuNSI+dG8gYSBvbmUtbGluZSBtZXRob2Q8L3RleHQ+CgogIDx0ZXh0IHg9IjgwMCIgeT0iMzQwIiBmaWxsPSIjYzRiNWZkIiBmb250LXNpemU9IjI1IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5TaXggaWRlbnRpY2FsIEJlc3Ugbm9kZXMuIE9uZSBsZWFrZWQgfjEwIEdCL2RheS4gVGhlIGNhdXNlIGJ1cm5lZCA4NCUgb2Ygb25lIG5vZGUncyBDUFUuPC90ZXh0PgoKICA8IS0tIGNvZGUgaGVybyAtLT4KICA8cmVjdCB4PSIzMDAiIHk9IjQwMCIgd2lkdGg9IjEwMDAiIGhlaWdodD0iMTE4IiByeD0iMTAiIGZpbGw9IiMwYjEwMjAiIHN0cm9rZT0iIzMzNDE1NSIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSIzNDAiIHk9IjQ1MiIgZmlsbD0iIzk0YTNiOCIgZm9udC1mYW1pbHk9Ik1lbmxvLCBDb25zb2xhcywgbW9ub3NwYWNlIiBmb250LXNpemU9IjI2Ij5wdWJsaWMgYm9vbGVhbiBpc0Nsb3NlZCgpIHs8L3RleHQ+CiAgPHRleHQgeD0iMzcyIiB5PSI0OTIiIGZpbGw9IiNmZGU2OGEiIGZvbnQtZmFtaWx5PSJNZW5sbywgQ29uc29sYXMsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIyNiI+cmV0dXJuIHBhcmVudC5pc0Nsb3NlZCgpOzwvdGV4dD4KICA8dGV4dCB4PSI5ODAiIHk9IjQ3OCIgZmlsbD0iIzk0YTNiOCIgZm9udC1mYW1pbHk9Ik1lbmxvLCBDb25zb2xhcywgbW9ub3NwYWNlIiBmb250LXNpemU9IjI2Ij59PC90ZXh0PgogIDxyZWN0IHg9IjEwNDAiIHk9IjQzMCIgd2lkdGg9IjIxMCIgaGVpZ2h0PSI1NiIgcng9IjI4IiBmaWxsPSJ1cmwoI2dyYWQtbGVhay10YikiLz4KICA8dGV4dCB4PSIxMTQ1IiB5PSI0NjciIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjYiIGZvbnQtd2VpZ2h0PSI3MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPjg0JSBvZiBDUFU8L3RleHQ+CgogIDwhLS0gbWluaSBkaXZlcmdlbmNlIHNwYXJrbGluZSAtLT4KICA8Zz4KICAgIDxsaW5lIHgxPSI0MzAiIHkxPSI2OTAiIHgyPSIxMTcwIiB5Mj0iNjkwIiBzdHJva2U9IiMyNDMwNTYiIHN0cm9rZS13aWR0aD0iMSIvPgogICAgPGxpbmUgeDE9IjQzMCIgeTE9IjYwMCIgeDI9IjExNzAiIHkyPSI2MDAiIHN0cm9rZT0iI2Y4NzE3MSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtZGFzaGFycmF5PSI3IDUiLz4KICAgIDx0ZXh0IHg9IjExNzAiIHk9IjU5MiIgZmlsbD0iI2ZjYTVhNSIgZm9udC1zaXplPSIxNiIgdGV4dC1hbmNob3I9ImVuZCI+T09NPC90ZXh0PgogICAgPGcgc3Ryb2tlPSIjMTRiOGE2IiBzdHJva2Utd2lkdGg9IjIuNSIgb3BhY2l0eT0iMC44NSI+CiAgICAgIDxsaW5lIHgxPSI0MzAiIHkxPSI2NzIiIHgyPSIxMTcwIiB5Mj0iNjcxIi8+CiAgICAgIDxsaW5lIHgxPSI0MzAiIHkxPSI2NzYiIHgyPSIxMTcwIiB5Mj0iNjc3Ii8+CiAgICAgIDxsaW5lIHgxPSI0MzAiIHkxPSI2ODAiIHgyPSIxMTcwIiB5Mj0iNjc5Ii8+CiAgICA8L2c+CiAgICA8dGV4dCB4PSI0MzAiIHk9IjcxMiIgZmlsbD0iIzVlZWFkNCIgZm9udC1zaXplPSIxNyI+QmVzdSArIDUgb3RoZXIgQ0NzOiBmbGF0IH4xIEdCPC90ZXh0PgogICAgPHBvbHlsaW5lIGZpbGw9Im5vbmUiIHN0cm9rZT0idXJsKCNncmFkLWxlYWstdGIpIiBzdHJva2Utd2lkdGg9IjQiIHBvaW50cz0iNDMwLDY3NiAxMTAwLDYwMCIvPgogICAgPGNpcmNsZSBjeD0iMTEwMCIgY3k9IjYwMCIgcj0iNiIgZmlsbD0iI2Y5NzMxNiIvPgogICAgPHRleHQgeD0iMTEyMCIgeT0iNjA2IiBmaWxsPSIjZmI5MjNjIiBmb250LXNpemU9IjE3IiBmb250LXdlaWdodD0iNjAwIj5CZXN1ICsgUHJ5c208L3RleHQ+CiAgPC9nPgoKICA8cmVjdCB4PSIxMDAiIHk9IjgwMCIgd2lkdGg9IjE0MDAiIGhlaWdodD0iNTAiIHJ4PSI0IiBmaWxsPSIjMWUyOTNiIiBzdHJva2U9IiMzMzQxNTUiIHN0cm9rZS13aWR0aD0iMSIvPgogIDx0ZXh0IHg9IjgwMCIgeT0iODMyIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjIwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5Gb3VuZCBieSBTdGVyZXVtTGFicyBBSSBvdmVyIGZsZWV0IHRlbGVtZXRyeSDCtyByZXBvcnRlZCBhcyBiZXN1LWV0aC9iZXN1IzEwNDk4IMK3IGZpeCBpbiByZXZpZXcgdXBzdHJlYW08L3RleHQ+CgogIDx0ZXh0IHg9IjEwMCIgeT0iODg4IiBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE2Ij7CqSBSb2NrTG9naWMgR21iSDwvdGV4dD4KICA8dGV4dCB4PSIxNTAwIiB5PSI4ODgiIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMTYiIHRleHQtYW5jaG9yPSJlbmQiPmRvY3Muc3RlcmV1bWxhYnMuY29tPC90ZXh0Pgo8L3N2Zz4K" width="1600" height="900" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="one-odd-node-out-of-six-is-a-signal-not-noise">One odd node out of six is a signal, not noise<a href="https://docs.stereumlabs.com/blog/besu-bonsai-layered-storage-memory-leak#one-odd-node-out-of-six-is-a-signal-not-noise" class="hash-link" aria-label="Direct link to One odd node out of six is a signal, not noise" title="Direct link to One odd node out of six is a signal, not noise" translate="no">​</a></h2>
<p>We run every major execution client paired with every major consensus client, on identical bare metal, with one telemetry pipeline across the whole set. The point of that layout is differential: when six Besu nodes share a version, a host spec, and a config, and differ only in their paired consensus client, any divergence between them isolates the variable for you. So one of six otherwise-identical Besu nodes leaking heap while its five siblings stay flat is not a mystery to explain away. It is a starting point.</p>
<p>StereumLabs AI sits on top of that telemetry. It read the divergence, formed a root-cause hypothesis, and walked it down to a single method. The steps below are ordinary observability: fleet Prometheus, JVM GC metrics, container logs, and one flight-recorder window. Nothing exotic.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-hunt">The hunt<a href="https://docs.stereumlabs.com/blog/besu-bonsai-layered-storage-memory-leak#the-hunt" class="hash-link" aria-label="Direct link to The hunt" title="Direct link to The hunt" translate="no">​</a></h2>
<p><strong>Isolate.</strong> A cross-pair comparison over fleet Prometheus showed five flat Besu nodes and one climbing. The leaking node was the Besu paired with Prysm v7.1.3. That alone narrowed the cause to something about that pairing, not Besu in general.</p>
<p><img decoding="async" loading="lazy" alt="JVM heap over 30 hours for the six Besu nodes: five flat near 1 GB, the Prysm-paired one rising linearly at about 10 GB per day toward the OOM ceiling" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNjAwIDkwMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPGRlZnM+CiAgICA8cGF0dGVybiBpZD0iZ3JpZC1oZCIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBwYXR0ZXJuVW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHBhdGggZD0iTSA4MCAwIEwgMCAwIDAgODAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIwLjUiLz4KICAgIDwvcGF0dGVybj4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZC1sZWFrIiB4MT0iMCUiIHkxPSIxMDAlIiB4Mj0iMTAwJSIgeTI9IjAlIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2I5MWMxYyIvPgogICAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmOTczMTYiLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgPC9kZWZzPgoKICA8cmVjdCB3aWR0aD0iMTYwMCIgaGVpZ2h0PSI5MDAiIGZpbGw9IiMwZTE1MzAiLz4KICA8cmVjdCB3aWR0aD0iMTYwMCIgaGVpZ2h0PSI5MDAiIGZpbGw9InVybCgjZ3JpZC1oZCkiLz4KICA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTYwMCIgaGVpZ2h0PSIxNCIgZmlsbD0iIzUwNDZlNSIvPgoKICA8dGV4dCB4PSIxMDAiIHk9IjEwMCIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIyOCIgZm9udC13ZWlnaHQ9IjYwMCI+U3RlcmV1bUxhYnM8L3RleHQ+CiAgPHRleHQgeD0iMTUwMCIgeT0iMTAwIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjIwIiB0ZXh0LWFuY2hvcj0iZW5kIj5KVk0gaGVhcCDCtyBzaXggQmVzdSAyNi40LjAgbm9kZXM8L3RleHQ+CgogIDx0ZXh0IHg9IjgwMCIgeT0iMTcyIiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjQ2IiBmb250LXdlaWdodD0iNzAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBsZXR0ZXItc3BhY2luZz0iLTEiPkZpdmUgZmxhdCwgb25lIGxlYWtpbmc8L3RleHQ+CiAgPHRleHQgeD0iODAwIiB5PSIyMTQiIGZpbGw9IiNjNGI1ZmQiIGZvbnQtc2l6ZT0iMjMiIHRleHQtYW5jaG9yPSJtaWRkbGUiPlNhbWUgQmVzdSB2ZXJzaW9uLCBoYXJkd2FyZSwgYW5kIGNvbmZpZy4gT25seSB0aGUgcGFpcmVkIGNvbnNlbnN1cyBjbGllbnQgZGlmZmVycy48L3RleHQ+CgogIDwhLS0geSBncmlkbGluZXMgKyBsYWJlbHM6IDAsNCw4LDEyLDE2IEdCIGF0IHkgNzYwLDYzMCw1MDAsMzcwLDI0MCAtLT4KICA8ZyBzdHJva2U9IiMyNDMwNTYiIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8bGluZSB4MT0iMjAwIiB5MT0iNzYwIiB4Mj0iMTQ4MCIgeTI9Ijc2MCIvPgogICAgPGxpbmUgeDE9IjIwMCIgeTE9IjYzMCIgeDI9IjE0ODAiIHkyPSI2MzAiLz4KICAgIDxsaW5lIHgxPSIyMDAiIHkxPSI1MDAiIHgyPSIxNDgwIiB5Mj0iNTAwIi8+CiAgICA8bGluZSB4MT0iMjAwIiB5MT0iMzcwIiB4Mj0iMTQ4MCIgeTI9IjM3MCIvPgogIDwvZz4KICA8ZyBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE4IiB0ZXh0LWFuY2hvcj0iZW5kIj4KICAgIDx0ZXh0IHg9IjE4MCIgeT0iNzY2Ij4wPC90ZXh0PgogICAgPHRleHQgeD0iMTgwIiB5PSI2MzYiPjQgR0I8L3RleHQ+CiAgICA8dGV4dCB4PSIxODAiIHk9IjUwNiI+OCBHQjwvdGV4dD4KICAgIDx0ZXh0IHg9IjE4MCIgeT0iMzc2Ij4xMiBHQjwvdGV4dD4KICAgIDx0ZXh0IHg9IjE4MCIgeT0iMjQ2Ij4xNiBHQjwvdGV4dD4KICA8L2c+CgogIDwhLS0gT09NIGNlaWxpbmcgYXQgfjEzLjUgR0IgLT4geT0zMjEgLS0+CiAgPGxpbmUgeDE9IjIwMCIgeTE9IjMyMSIgeDI9IjE0ODAiIHkyPSIzMjEiIHN0cm9rZT0iI2Y4NzE3MSIgc3Ryb2tlLXdpZHRoPSIyLjUiIHN0cm9rZS1kYXNoYXJyYXk9IjggNiIvPgogIDx0ZXh0IHg9IjE0NzYiIHk9IjMxMiIgZmlsbD0iI2ZjYTVhNSIgZm9udC1zaXplPSIxOSIgZm9udC13ZWlnaHQ9IjYwMCIgdGV4dC1hbmNob3I9ImVuZCI+T09NIGtpbGwsIH4zMCBoIGFmdGVyIHJlc3RhcnQ8L3RleHQ+CgogIDwhLS0gZml2ZSBmbGF0IGxpbmVzIG5lYXIgMS4wLTEuMyBHQiAoeSB+NzIwLTczMykgLS0+CiAgPGcgc3Ryb2tlPSIjMTRiOGE2IiBzdHJva2Utd2lkdGg9IjIuNSIgZmlsbD0ibm9uZSIgb3BhY2l0eT0iMC44NSI+CiAgICA8bGluZSB4MT0iMjAwIiB5MT0iNzIwIiB4Mj0iMTQ4MCIgeTI9IjcxOSIvPgogICAgPGxpbmUgeDE9IjIwMCIgeTE9IjcyNCIgeDI9IjE0ODAiIHkyPSI3MjUiLz4KICAgIDxsaW5lIHgxPSIyMDAiIHkxPSI3MjgiIHgyPSIxNDgwIiB5Mj0iNzI3Ii8+CiAgICA8bGluZSB4MT0iMjAwIiB5MT0iNzMxIiB4Mj0iMTQ4MCIgeTI9IjczMiIvPgogICAgPGxpbmUgeDE9IjIwMCIgeTE9IjczNCIgeDI9IjE0ODAiIHkyPSI3MzMiLz4KICA8L2c+CiAgPHRleHQgeD0iOTAwIiB5PSI3MDAiIGZpbGw9IiM1ZWVhZDQiIGZvbnQtc2l6ZT0iMjAiIGZvbnQtd2VpZ2h0PSI2MDAiPkJlc3UgKyA1IG90aGVyIENDczogZmxhdCB+MS4wIHRvIDEuMyBHQjwvdGV4dD4KCiAgPCEtLSBsZWFraW5nIGxpbmU6ICgyMDAsNzI3KSAtPiAoMTQwMCwzMjEpLCAxMCBHQi9kYXkgLS0+CiAgPHBvbHlsaW5lIGZpbGw9Im5vbmUiIHN0cm9rZT0idXJsKCNncmFkLWxlYWspIiBzdHJva2Utd2lkdGg9IjQuNSIgcG9pbnRzPSIyMDAsNzI3IDE0MDAsMzIxIi8+CiAgPGNpcmNsZSBjeD0iMTQwMCIgY3k9IjMyMSIgcj0iNyIgZmlsbD0iI2Y5NzMxNiIvPgogIDx0ZXh0IHg9Ijk4MCIgeT0iNDcwIiBmaWxsPSIjZmI5MjNjIiBmb250LXNpemU9IjIyIiBmb250LXdlaWdodD0iNzAwIiB0cmFuc2Zvcm09InJvdGF0ZSgtMTggOTgwIDQ3MCkiPkJlc3UgKyBQcnlzbTogfjEwIEdCL2RheTwvdGV4dD4KCiAgPCEtLSB4IGxhYmVscyAtLT4KICA8ZyBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj4KICAgIDx0ZXh0IHg9IjIwMCIgeT0iNzg4Ij4wIGg8L3RleHQ+CiAgICA8dGV4dCB4PSI2MDAiIHk9Ijc4OCI+MTAgaDwvdGV4dD4KICAgIDx0ZXh0IHg9IjEwMDAiIHk9Ijc4OCI+MjAgaDwvdGV4dD4KICAgIDx0ZXh0IHg9IjE0MDAiIHk9Ijc4OCI+MzAgaDwvdGV4dD4KICA8L2c+CgogIDx0ZXh0IHg9IjgwMCIgeT0iODQ1IiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5UaGUgbGVha2luZyBub2RlIGhhZCB0aGUgbG93ZXN0IGFsbG9jYXRpb24gcmF0ZSBvZiB0aGUgc2l4LiBUaGlzIGlzIHJldGFpbmVkIGxpdmUgZGF0YSwgbm90IGNodXJuLjwvdGV4dD4KCiAgPHRleHQgeD0iMTAwIiB5PSI4ODIiIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMTUiPsKpIFJvY2tMb2dpYyBHbWJIPC90ZXh0PgogIDx0ZXh0IHg9IjE1MDAiIHk9Ijg4MiIgZmlsbD0iIzk0YTNiOCIgZm9udC1zaXplPSIxNSIgdGV4dC1hbmNob3I9ImVuZCI+ZG9jcy5zdGVyZXVtbGFicy5jb208L3RleHQ+Cjwvc3ZnPgo=" width="1600" height="900" class="img_ev3q"></p>
<p><strong>Characterise.</strong> The garbage-collection signature said live leak, not allocation pressure. After every collection, Old Gen occupancy still climbed about 0.4 GB/h, and the leaking node had the lowest allocation rate of the six. Post-collection Old Gen used equalled live data: the collector had nothing left to reclaim. Heap was being retained, not churned.</p>
<p><strong>Corroborate.</strong> The leaking node emitted roughly seven times the log volume of the median Besu pair, dominated by one engine new-payload hot path: "block already present". It logged 53,756 <code>engine_newPayloadV4</code> calls in 17.5 hours, against a one-per-slot baseline near 5,250, for blocks it already had.</p>
<p><strong>Confirm.</strong> A Java Flight Recorder window settled it. About 84 percent of all CPU samples sat inside one method, <code>LayeredKeyValueStorage.isClosed()</code>, with most of the rest in the layered store's comparator. The chain head had not advanced in over 18 hours, despite tens of thousands of new-payload calls.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-root-cause-in-plain-terms">The root cause, in plain terms<a href="https://docs.stereumlabs.com/blog/besu-bonsai-layered-storage-memory-leak#the-root-cause-in-plain-terms" class="hash-link" aria-label="Direct link to The root cause, in plain terms" title="Direct link to The root cause, in plain terms" translate="no">​</a></h2>
<p>The cause sat in the seam between the two clients; the symptom showed up only on Besu.</p>
<p>On the consensus side, the paired Prysm had fallen behind and was catching up. It fed Besu a run of blocks through <code>engine_newPayload</code> without sending a <code>forkchoiceUpdated</code> between them. Many of those calls timed out from its HTTP client, so it retried, which is where the loud "block already present" log volume came from. The Prysm-side issue that drops it out of sync, and into this catch-up, is tracked in <a href="https://github.com/OffchainLabs/prysm/issues/16096" target="_blank" rel="noopener noreferrer" class="">OffchainLabs/prysm#16096</a>. Consensus clients that send a forkchoice update first, such as Lighthouse and Nimbus, take a different path on Besu and do not trigger it.</p>
<p>On the Besu side sat the part that had not been seen before. For each new block applied this way, Besu freezes a Bonsai <code>LayeredKeyValueStorage</code> and, on the no-forkchoice path, never closes it, so eviction falls to the garbage collector. Under sustained catch-up the layers pile up faster than the collector frees them. The repeat "block already present" calls do not add layers themselves, but every state access now has to check whether its layer is closed, and that check delegates straight up the parent chain:</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java 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">public boolean isClosed() {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  return parent.isClosed();</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>That one line runs on every state access. With a flat layer stack it is free. With a thousand-plus accumulated layers it becomes a walk up the entire parent chain on every access, which is why it rose to about 84 percent of CPU. Block validation could then no longer finish inside the engine timeout, so the chain head stalled, which made Prysm time out and retry more, which deepened the stack further. A self-reinforcing loop, with the heap curve in the chart above as its outward sign.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-shipped-what-reopened-it-and-the-fix">What shipped, what reopened it, and the fix<a href="https://docs.stereumlabs.com/blog/besu-bonsai-layered-storage-memory-leak#what-shipped-what-reopened-it-and-the-fix" class="hash-link" aria-label="Direct link to What shipped, what reopened it, and the fix" title="Direct link to What shipped, what reopened it, and the fix" translate="no">​</a></h2>
<p>We filed this as <a href="https://github.com/besu-eth/besu/issues/10498" target="_blank" rel="noopener noreferrer" class="">besu-eth/besu#10498</a>. Besu triaged it P2 and landed a set of mitigations:</p>
<ul>
<li class=""><a href="https://github.com/besu-eth/besu/pull/10508" target="_blank" rel="noopener noreferrer" class="">PR #10508</a> caches a layer's closed-state so the parent-chain walk can short-circuit.</li>
<li class="">Three allocation cleanups (<a href="https://github.com/besu-eth/besu/pull/10523" target="_blank" rel="noopener noreferrer" class="">#10523</a>, <a href="https://github.com/besu-eth/besu/pull/10526" target="_blank" rel="noopener noreferrer" class="">#10526</a>, <a href="https://github.com/besu-eth/besu/pull/10527" target="_blank" rel="noopener noreferrer" class="">#10527</a>) replace per-call exception objects with stackless singletons, cutting the GC pressure the stall generated.</li>
<li class=""><a href="https://github.com/besu-eth/besu/pull/10559" target="_blank" rel="noopener noreferrer" class="">PR #10559</a> caches the validated engine JWT so a consensus-client reconnect storm no longer forces a Besu restart.</li>
</ul>
<p>Those merged and the issue was closed on 2026-05-28. The direct structural fix, <a href="https://github.com/besu-eth/besu/pull/10509" target="_blank" rel="noopener noreferrer" class="">PR #10509</a>, which would have capped the layer stack and returned <code>SYNCING</code> past a bound, was closed on 2026-05-27 without merging.</p>
<p>It came back. On a mainnet nightly node running <code>26.6-develop</code> with Prysm 7.1.4, the heap climb returned, and Besu's maintainer reopened the issue on 2026-06-05. The <code>isClosed()</code> cache from #10508 only short-circuits once a layer is closed, and these layers are never closed, so a deep open chain still recurses fully on every call. The caches relieve the surrounding pressure. They do not stop the layers from accumulating.</p>
<p>To pin the mechanism down we built a Kurtosis devnet reproduction: a Besu 26.6.0 target paired with Prysm, plus two controls, the same Besu paired with Lighthouse and a Prysm paired with Geth. Stopping the target's Prysm, letting the network run ahead, then feeding the new blocks back through <code>engine_newPayloadV4</code> with no forkchoice update between calls drove the target from 58 to 1,362 retained layers while the control Besu stayed at 0. Replays of already-present blocks stayed flat over 5,000 calls, which isolated the growth to new blocks applied without an intervening forkchoice update. <code>isClosed()</code> was again the dominant cost, and <code>engine_newPayload</code> latency tracked the depth: about 3.5 ms against an already-present block near the top of the stack, rising to a median around 245 ms and up to 1.4 s at depth 1,300 to 1,500. On that evidence the issue was reopened, and this time the fix came quickly.</p>
<p>Besu opened <a href="https://github.com/besu-eth/besu/pull/10600" target="_blank" rel="noopener noreferrer" class="">PR #10600</a>, which returns <code>SYNCING</code> when the parent world state is not immediately cached. That routes a run of no-forkchoice new-payload calls into backward sync, the same path Lighthouse and Nimbus already take, instead of the trie-log replay that builds layers. Besu validated it against our Kurtosis file: on the unpatched 26.6.0 image, 30 new-payload calls in 437 ms with no forkchoice update between them left 30 unflushable Bonsai layers; on the patched build the same test left one layer, answered 27 of the calls with <code>SYNCING</code>, and recovered through backward sync in about two minutes. A companion change, <a href="https://github.com/besu-eth/besu/pull/10603" target="_blank" rel="noopener noreferrer" class="">PR #10603</a>, makes <code>LayeredKeyValueStorage.isClosed()</code> itself O(1), so the CPU hot path is gone even if a deep chain ever forms. Both are in review as of this writing, so the issue stays open until they land, but the fix is written and confirmed against the same reproduction that reopened it.</p>
<p>Credit to both teams. The Prysm-side sync loss is a known issue with a fix in progress, and Besu has been fast and precise on every round, turning our reproduction into a validated fix. Neither client is at fault in isolation; the bug lives in the seam between them, on a path that only a specific live pairing reaches.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-this-kind-of-bug-needs-a-fleet">Why this kind of bug needs a fleet<a href="https://docs.stereumlabs.com/blog/besu-bonsai-layered-storage-memory-leak#why-this-kind-of-bug-needs-a-fleet" class="hash-link" aria-label="Direct link to Why this kind of bug needs a fleet" title="Direct link to Why this kind of bug needs a fleet" translate="no">​</a></h2>
<p>A single Besu node, tested on its own with a healthy consensus client, will not show this. It needs a paired client that has fallen behind and is feeding new blocks through new-payload without forkchoice updates, sustained long enough for the layer stack to grow. It does not need an attacker: one restart that drops a consensus client into catch-up is enough. The operational bite is serious for the operator who hits it, a Besu that OOMs in about a day with the paired client churning peers and missing duties around it, but the path to seeing it at all runs through fleet-scale, differential observation.</p>
<p>That is what StereumLabs AI does on our fleet: it reads the telemetry across every client pairing, notices when one node stops matching its siblings, and turns the anomaly into something a client team can act on. If you run Ethereum clients at scale, you can point it at your own nodes and logs. Reach us at <a href="https://stereumlabs.com/" target="_blank" rel="noopener noreferrer" class="">stereumlabs.com</a> or <a href="mailto:contact@stereumlabs.com" target="_blank" rel="noopener noreferrer" class="">contact@stereumlabs.com</a>.</p>]]></content:encoded>
            <category>observability</category>
            <category>memory</category>
            <category>engine API</category>
            <category>Besu</category>
            <category>Prysm</category>
            <category>StereumLabs AI</category>
        </item>
        <item>
            <title><![CDATA[Ethereum EC pruning: disk size and the 4-second deadline]]></title>
            <link>https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour</link>
            <guid>https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour</guid>
            <pubDate>Wed, 03 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Six Ethereum execution clients, same hardware: disk from Erigon ~509 GB to Geth ~1.7 TB, and pruning can push newPayload past the 4s sync-committee deadline.]]></description>
            <content:encoded><![CDATA[<p>A <strong>Geth</strong> node and an <strong>Erigon</strong> node sit in the same rack, follow the same Ethereum mainnet, take the same engine-API traffic from their paired consensus clients. Today the Geth host's root filesystem reports <strong>~1,688 GB</strong> used. The Erigon host reports <strong>~509 GB</strong>. That is a <strong>3.3× spread</strong>, on the same chain, with no archive mode involved. Both are full nodes, both synced to mainnet head.</p>
<p>Disk is only half of it. The same pruning that bounds those footprints also runs on the engine-API hot path, and on some consensus-client pairings it pushes <code>engine_newPayload</code> past the <strong>4-second sync-committee deadline</strong>. This post covers both halves: how big each client gets and whether you can see it pruning, then what that pruning costs in latency once a node is at the tip.</p>
<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>Read this first</div><div class="admonitionContent_BuS1"><ul>
<li class=""><strong>Absolute disk numbers are upper bounds, not steady state.</strong> Every EC host here was rebuilt in the last <strong>7 to 16 days</strong> (we checked boot times and on-chain history). A fresh node has just finished an initial sync, whose on-disk layout is looser than a long-running, compacted one. The <strong>relative ordering</strong> (Erigon &lt; Ethrex &lt; Nethermind ≈ Besu &lt; Reth &lt; Geth) comes from architecture, not host age; read "Geth ~1.7 TB" as "heaviest by a wide margin," not a capacity-planning figure.</li>
<li class=""><strong>We run no validators on this fleet.</strong> The latency half measures <code>engine_newPayload</code>, the EC's slice of a validator's slot budget, not actual missed duties. Read those figures as a risk indicator, not a miss count.</li>
<li class=""><strong>newPayload P99 is observer-dependent.</strong> Each CC calls <code>notifyNewPayload</code> at a different point in the slot, so the same EC reads differently per CC. Nimbus is the headline; the full matrix is in the latency section.</li>
<li class=""><strong>Reth never finished syncing</strong> on this fleet, so it is excluded from the synced comparisons throughout (details in its section).</li>
</ul></div></div>
<p><img decoding="async" loading="lazy" alt="Datadir sizes per Ethereum execution client compared on identical hardware, ranging from Erigon ~509 GB to Geth ~1,688 GB" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNjAwIDkwMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPGRlZnM+CiAgICA8cGF0dGVybiBpZD0iZ3JpZC10aHVtYiIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBwYXR0ZXJuVW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHBhdGggZD0iTSA4MCAwIEwgMCAwIDAgODAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIwLjUiLz4KICAgIDwvcGF0dGVybj4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZC1nZXRoIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjEwMCUiIHkyPSIwJSI+CiAgICAgIDxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9IiNiOTFjMWMiLz4KICAgICAgPHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjZWE1ODBjIi8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXJldGgiIHgxPSIwJSIgeTE9IjAlIiB4Mj0iMTAwJSIgeTI9IjAlIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzlhMzQxMiIvPgogICAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmOTczMTYiLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImdyYWQtYmVzdSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMCUiPgogICAgICA8c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjODU0ZDBlIi8+CiAgICAgIDxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2VhYjMwOCIvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZC1uZXRoZXJtaW5kIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjEwMCUiIHkyPSIwJSI+CiAgICAgIDxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9IiMxZTQwYWYiLz4KICAgICAgPHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjM2I4MmY2Ii8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLWV0aHJleCIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMCUiPgogICAgICA8c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjN2MzYWVkIi8+CiAgICAgIDxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2E3OGJmYSIvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZC1lcmlnb24iIHgxPSIwJSIgeTE9IjAlIiB4Mj0iMTAwJSIgeTI9IjAlIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzBmNzY2ZSIvPgogICAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMxNGI4YTYiLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgPC9kZWZzPgoKICA8cmVjdCB3aWR0aD0iMTYwMCIgaGVpZ2h0PSI5MDAiIGZpbGw9IiMwZTE1MzAiLz4KICA8cmVjdCB3aWR0aD0iMTYwMCIgaGVpZ2h0PSI5MDAiIGZpbGw9InVybCgjZ3JpZC10aHVtYikiLz4KICA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTYwMCIgaGVpZ2h0PSIxNCIgZmlsbD0iIzUwNDZlNSIvPgoKICA8dGV4dCB4PSIxMDAiIHk9IjEwMCIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIyOCIgZm9udC13ZWlnaHQ9IjYwMCI+U3RlcmV1bUxhYnM8L3RleHQ+CiAgPHRleHQgeD0iMTUwMCIgeT0iMTAwIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjIwIiB0ZXh0LWFuY2hvcj0iZW5kIj43LWRheSBwcnVuaW5nIGNlbnN1czwvdGV4dD4KCiAgPHRleHQgeD0iODAwIiB5PSIyMDAiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iNTQiIGZvbnQtd2VpZ2h0PSI3MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGxldHRlci1zcGFjaW5nPSItMS41Ij5FQyBvbi1kaXNrIGZvb3RwcmludDogRXJpZ29uIDUwMCBHQiDCtyBHZXRoIDEuNyBUQjwvdGV4dD4KICA8dGV4dCB4PSI4MDAiIHk9IjI1MiIgZmlsbD0iI2M0YjVmZCIgZm9udC1zaXplPSIyNCIgZm9udC13ZWlnaHQ9IjQwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+My40w5cgc3ByZWFkIMK3IHNhbWUgY2hhaW4gwrcgc2FtZSBoYXJkd2FyZSDCtyBzaXggcHJ1bmluZyBzdXJmYWNlczwvdGV4dD4KCiAgPHRleHQgeD0iODAwIiB5PSIzMjAiIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMTgiIHRleHQtYW5jaG9yPSJtaWRkbGUiPlBlci1FQyByb290LWZpbGVzeXN0ZW0gdXNlZCBwZXIgaG9zdCBvbiBFdGhlcmV1bSBtYWlubmV0IMK3IHBvc3QtRnVzYWthIHdpbmRvdyDCtyBub2RlX2V4cG9ydGVyIGdyb3VuZCB0cnV0aDwvdGV4dD4KCiAgPCEtLSBCYXIgd2lkdGhzOiBzY2FsZSBzbyAxNjgxIEdCIChHZXRoKSA9IDkwMHB4LiBTbyAxIEdCIOKJiCAwLjUzNSBweC4KICAgICAgIEdldGggICAgIDE2ODEg4oaSIDkwMAogICAgICAgUmV0aCAgICAgMTM1NiDihpIgNzI2CiAgICAgICBCZXN1ICAgICAxMjU0IOKGkiA2NzEKICAgICAgIE5ldGhlcm1pbmQgMTIyMCDihpIgNjUzCiAgICAgICBFdGhyZXggICA1OTIgIOKGkiAzMTcKICAgICAgIEVyaWdvbiAgIDUwMCAg4oaSIDI2OCAtLT4KCiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjIwLCAzNzApIj4KICAgIDx0ZXh0IHg9IjAiIHk9IjM2IiBmaWxsPSIjZmNhNWE1IiBmb250LXNpemU9IjIyIiBmb250LXdlaWdodD0iNjAwIj5HZXRoPC90ZXh0PgogICAgPHJlY3QgeD0iMTkwIiB5PSIxNCIgd2lkdGg9IjkwMCIgaGVpZ2h0PSI0MiIgcng9IjMiIGZpbGw9InVybCgjZ3JhZC1nZXRoKSIvPgogICAgPHRleHQgeD0iMTEwNSIgeT0iNDQiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjYiIGZvbnQtd2VpZ2h0PSI3MDAiPjEsNjgxIEdCPC90ZXh0PgoKICAgIDx0ZXh0IHg9IjAiIHk9IjEwNiIgZmlsbD0iI2ZkYmE3NCIgZm9udC1zaXplPSIyMiIgZm9udC13ZWlnaHQ9IjYwMCI+UmV0aDwvdGV4dD4KICAgIDxyZWN0IHg9IjE5MCIgeT0iODQiIHdpZHRoPSI3MjYiIGhlaWdodD0iNDIiIHJ4PSIzIiBmaWxsPSJ1cmwoI2dyYWQtcmV0aCkiIG9wYWNpdHk9IjAuNSIgc3Ryb2tlPSIjZmJiZjI0IiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1kYXNoYXJyYXk9IjYgNSIvPgogICAgPHRleHQgeD0iOTMxIiB5PSIxMTQiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjYiIGZvbnQtd2VpZ2h0PSI3MDAiPjEsMzU2IEdCPC90ZXh0PgogICAgPHRleHQgeD0iMTA4NSIgeT0iMTE0IiBmaWxsPSIjZmJiZjI0IiBmb250LXNpemU9IjE3IiBmb250LXN0eWxlPSJpdGFsaWMiPm5vdCB5ZXQgc3luY2VkPC90ZXh0PgoKICAgIDx0ZXh0IHg9IjAiIHk9IjE3NiIgZmlsbD0iI2ZkZTY4YSIgZm9udC1zaXplPSIyMiIgZm9udC13ZWlnaHQ9IjYwMCI+QmVzdTwvdGV4dD4KICAgIDxyZWN0IHg9IjE5MCIgeT0iMTU0IiB3aWR0aD0iNjcxIiBoZWlnaHQ9IjQyIiByeD0iMyIgZmlsbD0idXJsKCNncmFkLWJlc3UpIi8+CiAgICA8dGV4dCB4PSI4NzYiIHk9IjE4NCIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIyNiIgZm9udC13ZWlnaHQ9IjcwMCI+MSwyNTQgR0I8L3RleHQ+CgogICAgPHRleHQgeD0iMCIgeT0iMjQ2IiBmaWxsPSIjYmZkYmZlIiBmb250LXNpemU9IjIyIiBmb250LXdlaWdodD0iNjAwIj5OZXRoZXJtaW5kPC90ZXh0PgogICAgPHJlY3QgeD0iMTkwIiB5PSIyMjQiIHdpZHRoPSI2NTMiIGhlaWdodD0iNDIiIHJ4PSIzIiBmaWxsPSJ1cmwoI2dyYWQtbmV0aGVybWluZCkiLz4KICAgIDx0ZXh0IHg9Ijg1OCIgeT0iMjU0IiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjI2IiBmb250LXdlaWdodD0iNzAwIj4xLDIyMCBHQjwvdGV4dD4KCiAgICA8dGV4dCB4PSIwIiB5PSIzMTYiIGZpbGw9IiNjNGI1ZmQiIGZvbnQtc2l6ZT0iMjIiIGZvbnQtd2VpZ2h0PSI2MDAiPkV0aHJleDwvdGV4dD4KICAgIDxyZWN0IHg9IjE5MCIgeT0iMjk0IiB3aWR0aD0iMzE3IiBoZWlnaHQ9IjQyIiByeD0iMyIgZmlsbD0idXJsKCNncmFkLWV0aHJleCkiLz4KICAgIDx0ZXh0IHg9IjUyMiIgeT0iMzI0IiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjI2IiBmb250LXdlaWdodD0iNzAwIj41OTIgR0I8L3RleHQ+CiAgICA8dGV4dCB4PSI2NTIiIHk9IjMyNCIgZmlsbD0iIzk0YTNiOCIgZm9udC1zaXplPSIxNyIgZm9udC1zdHlsZT0iaXRhbGljIj5ubyBwcnVuaW5nIG1ldHJpY3M8L3RleHQ+CgogICAgPHRleHQgeD0iMCIgeT0iMzg2IiBmaWxsPSIjNWVlYWQ0IiBmb250LXNpemU9IjIyIiBmb250LXdlaWdodD0iNjAwIj5Fcmlnb248L3RleHQ+CiAgICA8cmVjdCB4PSIxOTAiIHk9IjM2NCIgd2lkdGg9IjI2OCIgaGVpZ2h0PSI0MiIgcng9IjMiIGZpbGw9InVybCgjZ3JhZC1lcmlnb24pIi8+CiAgICA8dGV4dCB4PSI0NzMiIHk9IjM5NCIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIyNiIgZm9udC13ZWlnaHQ9IjcwMCI+NTAwIEdCPC90ZXh0PgogICAgPHRleHQgeD0iNjAzIiB5PSIzOTQiIGZpbGw9IiM1ZWVhZDQiIGZvbnQtc2l6ZT0iMTciIGZvbnQtc3R5bGU9Iml0YWxpYyI+YWdncmVzc2l2ZSBoaXN0b3J5IHBydW5pbmc8L3RleHQ+CiAgPC9nPgoKICA8cmVjdCB4PSIxMDAiIHk9IjgwMCIgd2lkdGg9IjE0MDAiIGhlaWdodD0iNTAiIHJ4PSI0IiBmaWxsPSIjMWUyOTNiIiBzdHJva2U9IiMzMzQxNTUiIHN0cm9rZS13aWR0aD0iMSIvPgogIDx0ZXh0IHg9IjgwMCIgeT0iODMyIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjIwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5DdW11bGF0aXZlIGZvb3RwcmludCBpcyB5ZWFycyBvZiByZXRlbnRpb24tcG9saWN5IGRpZmZlcmVuY2U7IHdlZWtseSBncm93dGggaXMgZG9taW5hdGVkIGJ5IG1haW5uZXQgYmxvY2stZGF0YSBpbmdlc3Rpb248L3RleHQ+CgogIDx0ZXh0IHg9IjEwMCIgeT0iODg4IiBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE2Ij7CqSBSb2NrTG9naWMgR21iSDwvdGV4dD4KICA8dGV4dCB4PSIxNTAwIiB5PSI4ODgiIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMTYiIHRleHQtYW5jaG9yPSJlbmQiPmRvY3Muc3RlcmV1bWxhYnMuY29tPC90ZXh0Pgo8L3N2Zz4K" width="1600" height="900" class="img_ev3q"></p>
<p><strong>Key findings:</strong></p>
<ul>
<li class=""><strong>3.3× footprint spread on the same chain</strong> (root-FS used per host): Erigon <strong>~509 GB</strong>, Ethrex ~598 GB, Nethermind ~1,225 GB, Besu ~1,261 GB, Reth ~1,352 GB (not synced), Geth <strong>~1,688 GB</strong>.</li>
<li class=""><strong>Five of six ECs grew 15 to 19 GB in the 7-day window</strong> (~2–3 GB/day, normal block ingestion). The cumulative spread comes from retention policy, not the past week's growth.</li>
<li class=""><strong>Each EC exposes a different pruning surface, and Ethrex exposes none.</strong> Erigon's domain pruner fires ~501 k <code>blocks</code> events per host per week; Nethermind's <code>Hybrid</code> pruner runs continuously at ~1,497 nodes/sec/host; Geth path-mode prunes implicitly; Ethrex has no pruning metric at all.</li>
<li class=""><strong>Reth is still in initial staged sync:</strong> its checkpoint sits ~70 to 130 k blocks behind the tip and is not advancing, so it is excluded from the synced comparisons.</li>
<li class=""><strong>From Nimbus, three of five synced ECs cross the 4-second deadline on P99 <code>engine_newPayload</code></strong> (Nethermind 4.44 s, Geth 4.67 s, Ethrex ≥5.00 s), <strong>but the ranking flips by consensus client.</strong> It is a pairing property, not a fixed EC property.</li>
<li class=""><strong>Nethermind's spikes trace to two deliberate v1.37.1 choices.</strong> <code>nethermind_pruning_time</code> spikes past 5 s, over the deadline, entirely from the in-memory pruner.</li>
<li class=""><strong>Sync-committee duties get hit before attestations.</strong> A late sync-committee message misses the next block's <code>sync_aggregate</code> outright; a late attestation still has one slot of grace.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-we-measured-the-stereumlabs-ethereum-execution-client-fleet">What we measured: the StereumLabs Ethereum execution-client fleet<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#what-we-measured-the-stereumlabs-ethereum-execution-client-fleet" class="hash-link" aria-label="Direct link to What we measured: the StereumLabs Ethereum execution-client fleet" title="Direct link to What we measured: the StereumLabs Ethereum execution-client fleet" translate="no">​</a></h2>
<p>The bare-metal NDC2 fleet in Vienna runs the full pairing matrix: every consensus client (Grandine, Lighthouse, Lodestar, Nimbus, Prysm, Teku) paired with every execution client (Besu, Erigon, Ethrex, Geth, Nethermind, Reth). The GCP comparator cohort runs only Geth on the EC side. Host counts: Geth 13 (7 NDC2 + 6 GCP), Besu 7, all others 6. Versions current at query time: Geth v1.17.3, Nethermind 1.37.2 (<code>PruningMode=Hybrid</code>), Reth v2.2.0, Besu 26.5.0, Erigon v3.4.1, Ethrex 13.0.0. Hardware setup is documented in <a class="" href="https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack">the StereumLabs measurement stack post</a>.</p>
<p>All counters come from our <code>prometheus-cold</code> datasource over a rolling 7-day window ending around 2026-05-28 12:00 UTC. Per-host averages divide each EC's totals by its live host count. Queries are in the methodology section. (Host ages range 7 to 16 days, per the caveat above; Besu and Ethrex hosts are youngest at ~8 days.)</p>
<p>Every EC exposes its own pruning vocabulary on Prometheus. No two share names, and one exposes nothing at all:</p>
<ul>
<li class=""><strong>Geth (path-mode):</strong> <code>pathdb_gc_node_count</code>, <code>pathdb_history_state_bytes_data</code>, <code>pathdb_history_state_time</code>. No explicit prune-event counter; pruning is structural to path-mode.</li>
<li class=""><strong>Nethermind (Hybrid):</strong> <code>nethermind_pruned_persisted_nodes_count</code>, <code>nethermind_deep_pruned_persisted_nodes_count</code>, <code>nethermind_pruning_time</code>, <code>nethermind_state_db_in_pruning_writes</code>, <code>nethermind_pruning_cutoff_blocknumber</code>. The most complete surface, with an explicit continuous-vs-deep split.</li>
<li class=""><strong>Besu (Bonsai):</strong> <code>besu_pruner_trie_log_added_to_prune_queue_total</code>, <code>besu_pruner_trie_log_pruned_from_queue_total</code>, <code>besu_pruner_trie_log_pruned_orphan_total</code>, plus the <code>besu_executors_ethscheduler_chaindatapruner_*</code> thread-pool view. Trie-log queue only.</li>
<li class=""><strong>Erigon:</strong> <code>prune_seconds_count</code> (per <code>type</code> label), <code>domain_prune_size</code>, <code>domain_prunable</code>, <code>domain_pruning_progress</code>, <code>domain_prune_took_bucket</code>. Domain-based, the cleanest cross-cutting surface.</li>
<li class=""><strong>Reth:</strong> <code>reth_pruner_duration_seconds</code>, <code>reth_pruner_segments_duration_seconds</code>, <code>reth_pruner_segments_highest_pruned_block</code>. Per-segment timing; only <code>SenderRecovery</code> is populated here.</li>
<li class=""><strong>Ethrex:</strong> no pruning metric at all. Operators derive pruning state from <code>datadir_size_bytes</code>.</li>
</ul>
<p>So "did my client prune in the last hour" is answerable for some ECs and unanswerable for others, before we look at a single number.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-big-are-the-datadirs">How big are the datadirs?<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#how-big-are-the-datadirs" class="hash-link" aria-label="Direct link to How big are the datadirs?" title="Direct link to How big are the datadirs?" translate="no">​</a></h2>
<p>The numbers below come from <code>node_filesystem_*</code> (root-FS used per host), not the EC-internal size metrics. Those internal metrics each report only a slice of the datadir and understate it by hundreds of GB; the <a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#methodology" class="">methodology</a> has the per-client gap analysis (it is what produced the wrong 26 GB Erigon figure). On these hosts the EC datadir lives on <code>/</code> and the CC runs elsewhere, so root-FS is EC datadir plus ~5 to 10 GB of OS and logs.</p>
<p><img decoding="async" loading="lazy" alt="Grouped bars per execution client showing how far each client&amp;#39;s own Prometheus size metric falls short of the node_exporter root-FS figure, from Erigon 26 vs 509 GB to Besu 0 vs 1,261 GB" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNjAwIDk4MCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPGRlZnM+CiAgICA8cGF0dGVybiBpZD0iZ3JpZC1nYXAiIHdpZHRoPSI4MCIgaGVpZ2h0PSI4MCIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CiAgICAgIDxwYXRoIGQ9Ik0gODAgMCBMIDAgMCAwIDgwIiBmaWxsPSJub25lIiBzdHJva2U9IiMxYzI2NTQiIHN0cm9rZS13aWR0aD0iMC41Ii8+CiAgICA8L3BhdHRlcm4+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImdyYWQtYnJhbmQtZ2FwIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjEwMCUiIHkyPSIwJSI+CiAgICAgIDxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9IiM1MDQ2ZTUiLz4KICAgICAgPHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjNzM4NGY1Ii8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogIDwvZGVmcz4KCiAgPHJlY3Qgd2lkdGg9IjE2MDAiIGhlaWdodD0iOTgwIiBmaWxsPSIjMGUxNTMwIi8+CiAgPHJlY3Qgd2lkdGg9IjE2MDAiIGhlaWdodD0iOTgwIiBmaWxsPSJ1cmwoI2dyaWQtZ2FwKSIvPgogIDxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxNjAwIiBoZWlnaHQ9IjE0IiBmaWxsPSIjNTA0NmU1Ii8+CgogIDx0ZXh0IHg9IjEwMCIgeT0iMTAwIiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjI4IiBmb250LXdlaWdodD0iNjAwIj5TdGVyZXVtTGFiczwvdGV4dD4KICA8dGV4dCB4PSIxNTAwIiB5PSIxMDAiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMjAiIHRleHQtYW5jaG9yPSJlbmQiPm9uLWRpc2sgc2l6ZTogbWV0cmljIHZzIHRydXRoPC90ZXh0PgoKICA8dGV4dCB4PSI4MDAiIHk9IjE4NSIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSI1MCIgZm9udC13ZWlnaHQ9IjcwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgbGV0dGVyLXNwYWNpbmc9Ii0xLjIiPkVDLWludGVybmFsIG1ldHJpY3MgdW5kZXJzdGF0ZSBkaXNrIGJ5IGh1bmRyZWRzIG9mIEdCPC90ZXh0PgogIDx0ZXh0IHg9IjgwMCIgeT0iMjMyIiBmaWxsPSIjYzRiNWZkIiBmb250LXNpemU9IjI0IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5GaWxsZWQgYmFyID0gd2hhdCB0aGUgY2xpZW50J3Mgb3duIFByb21ldGhldXMgbWV0cmljIHJlcG9ydHMuIEZ1bGwgbGVuZ3RoID0gbm9kZV9leHBvcnRlciByb290LUZTLjwvdGV4dD4KCiAgPCEtLSBsZWdlbmQgLS0+CiAgPHJlY3QgeD0iNTYwIiB5PSIyNzYiIHdpZHRoPSIyNiIgaGVpZ2h0PSIxOCIgcng9IjMiIGZpbGw9InVybCgjZ3JhZC1icmFuZC1nYXApIi8+CiAgPHRleHQgeD0iNTk0IiB5PSIyOTEiIGZpbGw9IiNjYmQ1ZTEiIGZvbnQtc2l6ZT0iMTkiPkVDLWludGVybmFsIG1ldHJpYzwvdGV4dD4KICA8cmVjdCB4PSI4MjAiIHk9IjI3NiIgd2lkdGg9IjI2IiBoZWlnaHQ9IjE4IiByeD0iMyIgZmlsbD0iIzMzNDE1NSIvPgogIDx0ZXh0IHg9Ijg1NCIgeT0iMjkxIiBmaWxsPSIjY2JkNWUxIiBmb250LXNpemU9IjE5Ij53aGF0IGl0IG1pc3NlcyAocm9vdC1GUyB0cnV0aCk8L3RleHQ+CgogIDwhLS0gcm93czogc2NhbGUgMC43MTA5IHB4L0dCLCB4MD0zMDAgLS0+CiAgPGc+CiAgICA8dGV4dCB4PSI2MCIgeT0iMzg4IiBmaWxsPSIjNWVlYWQ0IiBmb250LXNpemU9IjI0IiBmb250LXdlaWdodD0iNjAwIj5Fcmlnb248L3RleHQ+CiAgICA8cmVjdCB4PSIzMDAiIHk9IjM2MCIgd2lkdGg9IjM2MiIgaGVpZ2h0PSI0MiIgcng9IjMiIGZpbGw9IiMzMzQxNTUiLz4KICAgIDxyZWN0IHg9IjMwMCIgeT0iMzYwIiB3aWR0aD0iMTgiIGhlaWdodD0iNDIiIHJ4PSIzIiBmaWxsPSJ1cmwoI2dyYWQtYnJhbmQtZ2FwKSIvPgogICAgPHRleHQgeD0iNjc2IiB5PSIzODgiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjIiIGZvbnQtd2VpZ2h0PSI2MDAiPjI2IOKGkiA1MDkgR0I8L3RleHQ+CgogICAgPHRleHQgeD0iNjAiIHk9IjQ4MCIgZmlsbD0iI2M0YjVmZCIgZm9udC1zaXplPSIyNCIgZm9udC13ZWlnaHQ9IjYwMCI+RXRocmV4PC90ZXh0PgogICAgPHJlY3QgeD0iMzAwIiB5PSI0NTIiIHdpZHRoPSI0MjUiIGhlaWdodD0iNDIiIHJ4PSIzIiBmaWxsPSIjMzM0MTU1Ii8+CiAgICA8cmVjdCB4PSIzMDAiIHk9IjQ1MiIgd2lkdGg9IjM1NSIgaGVpZ2h0PSI0MiIgcng9IjMiIGZpbGw9InVybCgjZ3JhZC1icmFuZC1nYXApIi8+CiAgICA8dGV4dCB4PSI3MzkiIHk9IjQ4MCIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIyMiIgZm9udC13ZWlnaHQ9IjYwMCI+NDk5IOKGkiA1OTggR0I8L3RleHQ+CgogICAgPHRleHQgeD0iNjAiIHk9IjU3MiIgZmlsbD0iI2JmZGJmZSIgZm9udC1zaXplPSIyNCIgZm9udC13ZWlnaHQ9IjYwMCI+TmV0aGVybWluZDwvdGV4dD4KICAgIDxyZWN0IHg9IjMwMCIgeT0iNTQ0IiB3aWR0aD0iODcxIiBoZWlnaHQ9IjQyIiByeD0iMyIgZmlsbD0iIzMzNDE1NSIvPgogICAgPHJlY3QgeD0iMzAwIiB5PSI1NDQiIHdpZHRoPSI1NTMiIGhlaWdodD0iNDIiIHJ4PSIzIiBmaWxsPSJ1cmwoI2dyYWQtYnJhbmQtZ2FwKSIvPgogICAgPHRleHQgeD0iMTE4NSIgeT0iNTcyIiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjIyIiBmb250LXdlaWdodD0iNjAwIj43Nzgg4oaSIDEsMjI1IEdCPC90ZXh0PgoKICAgIDx0ZXh0IHg9IjYwIiB5PSI2NjQiIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMjQiIGZvbnQtd2VpZ2h0PSI2MDAiPkJlc3U8L3RleHQ+CiAgICA8cmVjdCB4PSIzMDAiIHk9IjYzNiIgd2lkdGg9Ijg5NiIgaGVpZ2h0PSI0MiIgcng9IjMiIGZpbGw9IiMzMzQxNTUiLz4KICAgIDx0ZXh0IHg9IjMxMiIgeT0iNjY0IiBmaWxsPSIjY2JkNWUxIiBmb250LXNpemU9IjE5IiBmb250LXN0eWxlPSJpdGFsaWMiPm1ldHJpYyByZXR1cm5zIDA8L3RleHQ+CiAgICA8dGV4dCB4PSIxMjEwIiB5PSI2NjQiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjIiIGZvbnQtd2VpZ2h0PSI2MDAiPjAg4oaSIDEsMjYxIEdCPC90ZXh0PgoKICAgIDx0ZXh0IHg9IjYwIiB5PSI3NTYiIGZpbGw9IiNmZGJhNzQiIGZvbnQtc2l6ZT0iMjQiIGZvbnQtd2VpZ2h0PSI2MDAiPlJldGg8L3RleHQ+CiAgICA8cmVjdCB4PSIzMDAiIHk9IjcyOCIgd2lkdGg9Ijk2MSIgaGVpZ2h0PSI0MiIgcng9IjMiIGZpbGw9IiMzMzQxNTUiLz4KICAgIDxyZWN0IHg9IjMwMCIgeT0iNzI4IiB3aWR0aD0iMTQzIiBoZWlnaHQ9IjQyIiByeD0iMyIgZmlsbD0idXJsKCNncmFkLWJyYW5kLWdhcCkiLz4KICAgIDx0ZXh0IHg9IjEyNzUiIHk9Ijc1NiIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIyMiIgZm9udC13ZWlnaHQ9IjYwMCI+MjAxIOKGkiAxLDM1MiBHQjwvdGV4dD4KICAgIDx0ZXh0IHg9IjEyNzUiIHk9Ijc4MCIgZmlsbD0iIzk0YTNiOCIgZm9udC1zaXplPSIxNiIgZm9udC1zdHlsZT0iaXRhbGljIj5zdGlsbCBzbmFwLXN5bmNpbmc8L3RleHQ+CgogICAgPHRleHQgeD0iNjAiIHk9Ijg0OCIgZmlsbD0iI2ZjYTVhNSIgZm9udC1zaXplPSIyNCIgZm9udC13ZWlnaHQ9IjYwMCI+R2V0aDwvdGV4dD4KICAgIDxyZWN0IHg9IjMwMCIgeT0iODIwIiB3aWR0aD0iMTIwMCIgaGVpZ2h0PSI0MiIgcng9IjMiIGZpbGw9IiMzMzQxNTUiLz4KICAgIDxyZWN0IHg9IjMwMCIgeT0iODIwIiB3aWR0aD0iMTE1NSIgaGVpZ2h0PSI0MiIgcng9IjMiIGZpbGw9InVybCgjZ3JhZC1icmFuZC1nYXApIi8+CiAgICA8dGV4dCB4PSIxMTQwIiB5PSI4NDgiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjIiIGZvbnQtd2VpZ2h0PSI3MDAiPjEsNjI0IOKGkiAxLDY4OCBHQjwvdGV4dD4KICA8L2c+CgogIDx0ZXh0IHg9IjEwMCIgeT0iOTM1IiBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE2Ij7CqSBSb2NrTG9naWMgR21iSDwvdGV4dD4KICA8dGV4dCB4PSIxNTAwIiB5PSI5MzUiIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMTYiIHRleHQtYW5jaG9yPSJlbmQiPmRvY3Muc3RlcmV1bWxhYnMuY29tPC90ZXh0Pgo8L3N2Zz4K" width="1600" height="980" class="img_ev3q"></p>
<p><em>Every EC's own size metric understates its real disk use. Erigon's <code>db_table_size_bytes</code> sees 26 GB of a 509 GB datadir; Besu's RocksDB metric reports 0.</em></p>
<table><thead><tr><th>EC</th><th style="text-align:right">root-FS used (current)</th><th style="text-align:right">range across hosts</th><th style="text-align:right">7-day net delta</th><th>Sync state</th></tr></thead><tbody><tr><td>Erigon v3.4.1</td><td style="text-align:right"><strong>~509 GB</strong></td><td style="text-align:right">444 – 548 GB</td><td style="text-align:right">+17.7 GB</td><td>synced ✓</td></tr><tr><td>Ethrex 13.0.0</td><td style="text-align:right">~598 GB</td><td style="text-align:right">597 – 598 GB</td><td style="text-align:right">+15.3 GB</td><td>synced ✓</td></tr><tr><td>Nethermind 1.37.2</td><td style="text-align:right">~1,225 GB</td><td style="text-align:right">1,218 – 1,226 GB</td><td style="text-align:right">+16.2 GB</td><td>synced ✓</td></tr><tr><td>Besu 26.5.0</td><td style="text-align:right">~1,261 GB</td><td style="text-align:right">1,254 – 1,262 GB</td><td style="text-align:right">+18.6 GB</td><td>synced ✓</td></tr><tr><td>Reth v2.2.0</td><td style="text-align:right">~1,352 GB</td><td style="text-align:right">1,214 – 1,416 GB</td><td style="text-align:right">+112 GB</td><td><strong>not synced</strong> (staged sync, ~127k behind)</td></tr><tr><td>Geth v1.17.3</td><td style="text-align:right"><strong>~1,688 GB</strong></td><td style="text-align:right">1,633 – 1,733 GB</td><td style="text-align:right">+16.2 GB</td><td>synced ✓</td></tr></tbody></table>
<p>A head-block metric is <a class="" href="https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026">not a reliable sign that an EC is actually synced</a> (a client can follow the consensus layer's forkchoice head optimistically while still syncing), so we confirmed each one from its <strong>own container logs</strong>, not just its metrics. Five of six are importing at the tip in real time: Geth logs <code>Imported new potential chain segment</code>, Nethermind <code>Synced Chain Head to 25213…</code>, Besu <code>AbstractEngineNewPayload | Imported #25,213,…</code>, Erigon <code>Post-Forkchoice prune … initialCycle=false</code>, and Ethrex <code>[METRIC] BLOCK 25213… exec … 99% BOTTLENECK</code> (slow per block, but genuinely executing at the tip). <strong>Reth is the exception</strong> and gets its own section below; read its 1,352 GB as mid-sync state.</p>
<p>The 3.3× spread comes from retention architecture: Erigon drops account, storage, and block-body history once fork-choice no longer needs it and keeps no ancient store, while Geth path-mode adds a continuously growing ancient store on top of its bounded state journal. The per-week growth is the same ~16 GB across the synced clients (normal block ingestion); only the <em>starting</em> footprint differs. The per-client sections below break down each mechanism. It is the storage-side version of what the <a class="" href="https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026">EC sync-speed comparison</a> found on the same fleet: same hardware, same chain, very different footprints.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="geth-path-mode-prunes-implicitly">Geth: path-mode prunes implicitly<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#geth-path-mode-prunes-implicitly" class="hash-link" aria-label="Direct link to Geth: path-mode prunes implicitly" title="Direct link to Geth: path-mode prunes implicitly" translate="no">​</a></h2>
<p>Geth v1.17.3 runs path-based storage. Historical trie nodes for each state transition flow into a bounded "state history" journal and drop out as new history is written. There is no prune event; the boundedness is the prune. Three metrics show it:</p>
<ul>
<li class=""><code>pathdb_gc_node_count</code>: <strong>~300 M nodes garbage-collected per host since startup</strong> (291 M to 301 M across our 13 hosts), growing monotonically as path-mode GC trims old tries.</li>
<li class=""><code>pathdb_history_state_bytes_data</code>: <strong>1.33 GB per host</strong>, barely moving. The state-history journal, bounded by <code>--history.state</code> (default 90,000 blocks).</li>
<li class=""><code>pathdb_history_state_time</code> p99: <strong>510 µs to 1.29 ms</strong> per host (one GCP host at 1.66 ms). Time to write a single state-history block.</li>
</ul>
<p>Geth exposes no per-cycle prune counter and no cutoff block. The only health signal is <code>pathdb_history_state_time</code> p99 climbing over hours, which means the pruner is falling behind writes, though it will not tell you whether the pruner or the writes are the slow part.</p>
<p>Geth's +16.2 GB/week is ancient-store growth, not state. The ancient store holds frozen headers, bodies, and receipts that path-mode never touches, and at ~1,688 GB it is the bulk of Geth's footprint. Bounding total Geth disk needs separate <code>--history.transactions</code> and <code>--history.logs</code> flags, left at defaults here.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="nethermind-the-most-complete-pruning-surface">Nethermind: the most complete pruning surface<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#nethermind-the-most-complete-pruning-surface" class="hash-link" aria-label="Direct link to Nethermind: the most complete pruning surface" title="Direct link to Nethermind: the most complete pruning surface" translate="no">​</a></h2>
<p>Nethermind 1.37.2 with <code>PruningMode=Hybrid</code> is the only EC that exposes both continuous and deep pruning as distinct counters. The series that matter:</p>
<ul>
<li class=""><code>nethermind_pruned_persisted_nodes_count</code>: <strong>~1.13 billion increments in 7 days</strong>, ~<strong>1,497 nodes/sec/host</strong> (range 1,478 to 1,517).</li>
<li class=""><code>nethermind_deep_pruned_persisted_nodes_count</code>: full-prune count. Zero on every host.</li>
<li class=""><code>nethermind_state_db_in_pruning_writes</code>: <strong>0.33 to 0.41</strong>, so the state DB is in a pruning write roughly a third of the time.</li>
<li class=""><code>nethermind_pruning_cutoff_blocknumber</code>: <strong>0 across every host</strong>. On <code>Hybrid</code>, that means the deep-prune branch has never fired.</li>
<li class=""><code>nethermind_pruning_time</code>, <code>nethermind_pruning_cutoff_timestamp</code>: cycle duration and cutoff in epoch seconds.</li>
</ul>
<p>So the continuous in-memory pruner does all the work in our window and the deep prune has not been needed. On <code>nethermind_db_size</code> the state DB stays roughly flat, but the full datadir (receipts, indexes, logs) still grows ~16 GB/week, so monitor root-FS for capacity, not <code>nethermind_db_size</code>. That continuous pruner is also what makes <code>engine_newPayload</code> spike on this version, covered in the latency section below.</p>
<p>Nethermind is the easiest EC to alert on: <code>rate(nethermind_pruned_persisted_nodes_count[5m]) + rate(nethermind_deep_pruned_persisted_nodes_count[5m])</code> from the public <a href="https://grafana.stereumlabs.com/d/la6m5h5/nethermind-dashboard" target="_blank" rel="noopener noreferrer" class="">Nethermind dashboard</a> gives pruning throughput in nodes/sec. That rate dropping while disk grows means the pruner stalled.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="reth-still-in-initial-sync-so-its-pruning-is-not-yet-observable">Reth: still in initial sync, so its pruning is not yet observable<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#reth-still-in-initial-sync-so-its-pruning-is-not-yet-observable" class="hash-link" aria-label="Direct link to Reth: still in initial sync, so its pruning is not yet observable" title="Direct link to Reth: still in initial sync, so its pruning is not yet observable" translate="no">​</a></h2>
<p>Reth v2.2.0 has not finished its initial <strong>staged sync</strong> on any of our six hosts, and still had not as of this writing. Its container logs show the <code>sync::stages</code> pipeline still running rather than importing at the tip, and the metrics agree: the staged-sync checkpoint sits ~75 to 135 k blocks behind the tip and <strong>has not advanced in 12 hours</strong> on any host, the final pipeline stages (<code>Finish</code>, <code>TransactionLookup</code>, the history indexes) are still at 0, <code>reth_blockchain_tree_canonical_chain_height</code> is 0, and every newPayload returns SYNCING, never VALID. The process is alive (CPU and disk I/O are non-zero, with static-file rewrites both adding and reclaiming tens of GB), it just is not catching up. We cannot say from one fleet whether the stall is the client or something in our deployment, so we are not drawing any conclusion about Reth beyond "not comparable here."</p>
<p>So Reth's pruning is genuinely unmeasured. Its pruner has only ever run the one startup pass on the <code>SenderRecovery</code> segment (<code>reth_pruner_duration_seconds_count</code> is 0 or 1 per host). The ~1,352 GB on disk is mid-sync state, not a steady-state footprint, and Reth's documented engine backpressure (<a href="https://github.com/paradigmxyz/reth/issues/3428" target="_blank" rel="noopener noreferrer" class=""><code>reth_consensus_engine_beacon_backpressure_active</code></a>) never activates because the node never reaches steady state. We will rerun the comparison once these hosts finish syncing.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="besu-trie-log-pruning-is-the-only-window-into-bonsai-cleanup">Besu: trie-log pruning is the only window into Bonsai cleanup<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#besu-trie-log-pruning-is-the-only-window-into-bonsai-cleanup" class="hash-link" aria-label="Direct link to Besu: trie-log pruning is the only window into Bonsai cleanup" title="Direct link to Besu: trie-log pruning is the only window into Bonsai cleanup" translate="no">​</a></h2>
<p>Besu 26.5.0 runs Bonsai. Its pruning surface is narrower than Nethermind's and focused on the trie-log queue, the per-block diffs Bonsai keeps for reorg handling and historical queries:</p>
<ul>
<li class=""><code>besu_pruner_trie_log_pruned_from_queue_total</code>: <strong>~352 k trie logs pruned in 7 days</strong>, ~<strong>50,343 per host per day</strong>.</li>
<li class=""><code>besu_pruner_trie_log_added_to_prune_queue_total</code>: logs enqueued. The queue-minus-pruned difference is the backlog.</li>
<li class=""><code>besu_pruner_trie_log_pruned_orphan_total</code>: logs marked for deletion with no matching entry. A corruption signal; expect near zero.</li>
<li class=""><code>besu_executors_ethscheduler_chaindatapruner_*</code>: thread-pool view, confirms the pruner scheduler is alive.</li>
</ul>
<p>Besu exposes no Bonsai state size, no cutoff block, and no total disk figure (<code>besu_rocksdb_rocks_db_files_size_bytes</code> returns 0 here, an instrumentation gap). You read total Besu disk from <code>node_filesystem_*</code>. And the 50 k logs/day figure does not convert to bytes, since trie-log size varies per block with transaction mix, so it is a heartbeat, not a capacity input.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="erigon-the-smallest-footprint-in-the-fleet-by-a-wide-margin">Erigon: the smallest footprint in the fleet, by a wide margin<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#erigon-the-smallest-footprint-in-the-fleet-by-a-wide-margin" class="hash-link" aria-label="Direct link to Erigon: the smallest footprint in the fleet, by a wide margin" title="Direct link to Erigon: the smallest footprint in the fleet, by a wide margin" translate="no">​</a></h2>
<p>Erigon v3.4.1 runs domain-based pruning across three named domains: <code>blocks</code> (block bodies and headers), <code>state</code> (account and storage state), and <code>bor</code> (Polygon-specific; always 0 on Ethereum mainnet). The Prometheus surface follows that decomposition:</p>
<ul>
<li class=""><code>prune_seconds_count{type=blocks}</code>: ~<strong>501 k prune events per host in 7 days</strong> (460 k to 528 k), about one every 1.2 seconds.</li>
<li class=""><code>prune_seconds_count{type=state}</code>: ~<strong>50,775 events per host in 7 days</strong>, about one every 12 seconds.</li>
<li class=""><code>prune_seconds</code> averages: <strong>~1 ms</strong> per blocks prune, <strong>~12 ms</strong> per state prune.</li>
<li class=""><code>domain_prune_size</code>, <code>domain_prunable</code>, <code>domain_pruning_progress</code>: per-domain queue gauges, for confirming the backlog stays bounded.</li>
</ul>
<p>Erigon's root-FS sits at <strong>~509 GB, ~3× below the heaviest EC</strong>. Its weekly growth (+17.7 GB) matches everyone else's; only the cumulative footprint is smaller, because of the aggressive history retention. (The 26 GB an earlier draft quoted was the MDBX-only <code>db_table_size_bytes</code>; the snapshot and history files make up the rest.)</p>
<p>A Caplin standalone host (Erigon's built-in CL) shows the same <code>prune_seconds_count</code> series under <code>job="caplin"</code>, and its root-FS sits at 525 GB, only ~25 GB above a plain Erigon host despite carrying the CL in the same binary. Details in <a class="" href="https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos">the Erigon + Caplin standalone vs classic post</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ethrex-pruning-is-invisible-from-prometheus">Ethrex: pruning is invisible from Prometheus<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#ethrex-pruning-is-invisible-from-prometheus" class="hash-link" aria-label="Direct link to Ethrex: pruning is invisible from Prometheus" title="Direct link to Ethrex: pruning is invisible from Prometheus" translate="no">​</a></h2>
<p>Ethrex 13.0.0 exposes no pruning metric. <code>list_prometheus_metric_names</code> for <code>ethrex_.*</code> returns 31 series (peer counts, sync stages, discovery), none describing pruning, retention, or reclamation. The only disk signal is <code>datadir_size_bytes</code>, which matched <code>node_filesystem_*</code> to within ~100 GB and grew <strong>+15.3 GB/week per host</strong>.</p>
<p>Root-FS sits at ~598 GB, smaller than every EC except Erigon, so some retention bound is clearly in effect. But you cannot see when Ethrex prunes, how much it reclaims, or whether the pruner stalled. The <a href="https://grafana.stereumlabs.com/d/laf8s92/ethrex-dashboard" target="_blank" rel="noopener noreferrer" class="">Ethrex dashboard</a> has one disk panel ("DB Size On Disk Total") and no pruning section.</p>
<p>For operators that is the tradeoff: a young Rust client with the smallest metrics surface and no first-class pruning observability. It is fixable by adding instrumentation to the existing metrics endpoint, not a storage-layer limitation. We are happy to coordinate the metric shape with the Ethrex team.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pruning-vs-the-4-second-sync-committee-deadline">Pruning vs the 4-second sync-committee deadline<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#pruning-vs-the-4-second-sync-committee-deadline" class="hash-link" aria-label="Direct link to Pruning vs the 4-second sync-committee deadline" title="Direct link to Pruning vs the 4-second sync-committee deadline" translate="no">​</a></h2>
<p>The footprints above are the static picture. The operational question is what the pruner does to the engine-API hot path while a node is at the tip. Sync-committee messages and attestations both need to be ready ~4 seconds into the slot. A P99 <code>engine_newPayload</code> above that ceiling means a tail of slots where the CC builds duties against a stale head. Measured from each Nimbus host on <code>engine_api_request_duration_seconds_bucket{request="newPayload"}</code>, 7-day window:</p>
<table><thead><tr><th>EC</th><th style="text-align:right">Nimbus P99 newPayload</th><th>vs. 4 s deadline</th><th>Sync state</th></tr></thead><tbody><tr><td>Reth v2.2.0</td><td style="text-align:right">0.23 s</td><td>excluded</td><td><strong>not synced (returns SYNCING)</strong></td></tr><tr><td>Besu 26.5.0</td><td style="text-align:right">1.07 s</td><td>safe</td><td>synced</td></tr><tr><td>Erigon v3.4.1</td><td style="text-align:right">2.19 s</td><td>safe</td><td>synced</td></tr><tr><td>Nethermind 1.37.2</td><td style="text-align:right">4.44 s</td><td><strong>over deadline</strong></td><td>synced</td></tr><tr><td>Geth v1.17.3</td><td style="text-align:right">4.67 s</td><td><strong>over deadline</strong></td><td>synced</td></tr><tr><td>Ethrex 13.0.0</td><td style="text-align:right">≥5.00 s</td><td>top-bucket capped, worse</td><td>synced</td></tr></tbody></table>
<p>Three of the five synced clients sit over 4 s from Nimbus. Ethrex's value is at the histogram's top bucket (5.00 s), so the true P99 is higher; we write <code>≥5.00 s</code>, and it is a slow-block-validation problem rather than pruning per se. The order tracks the per-client mechanisms above: Besu prunes off-thread, Erigon prunes in a fast stage, and Nethermind, Geth, and Ethrex all touch the engine thread during pruning. Reth's 0.23 s is the SYNCING return path, not block execution, so it is excluded.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-ranking-flips-by-observer">The ranking flips by observer<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#the-ranking-flips-by-observer" class="hash-link" aria-label="Direct link to The ranking flips by observer" title="Direct link to The ranking flips by observer" translate="no">​</a></h3>
<p>Three CCs export a newPayload histogram: Nimbus (<code>engine_api_request_duration_seconds</code>), Lighthouse (<code>execution_layer_request_times</code>), and Prysm/Lodestar (<code>new_payload_v1_latency_milliseconds</code>). Teku does not. Each calls <code>notifyNewPayload</code> at a different point relative to gossip validation, so the same EC reads differently:</p>
<table><thead><tr><th>EC</th><th style="text-align:right">Nimbus P99</th><th style="text-align:right">Lighthouse P99</th><th style="text-align:right">Prysm P99</th><th>Notes</th></tr></thead><tbody><tr><td>Reth</td><td style="text-align:right">0.23 s</td><td style="text-align:right">0.97 s</td><td style="text-align:right">4.00 s (capped)</td><td><strong>all not synced, SYNCING on every CC</strong></td></tr><tr><td>Besu</td><td style="text-align:right">1.07 s</td><td style="text-align:right"><strong>4.86 s</strong></td><td style="text-align:right">3.91 s</td><td>synced</td></tr><tr><td>Erigon</td><td style="text-align:right">2.19 s</td><td style="text-align:right">n/a</td><td style="text-align:right">3.49 s</td><td>synced</td></tr><tr><td>Nethermind</td><td style="text-align:right"><strong>4.44 s</strong></td><td style="text-align:right">1.40 s</td><td style="text-align:right">1.05 s</td><td>synced</td></tr><tr><td>Geth</td><td style="text-align:right">4.67 s</td><td style="text-align:right">4.63 s</td><td style="text-align:right">3.41 s</td><td>synced</td></tr><tr><td>Ethrex</td><td style="text-align:right">≥5.00 s</td><td style="text-align:right">4.49 s</td><td style="text-align:right">3.55 s</td><td>synced</td></tr></tbody></table>
<p><img decoding="async" loading="lazy" alt="Grouped bars per execution client with one bar per consensus client observer (Nimbus, Lighthouse, Prysm) against a 4-second deadline line, showing Nethermind over the line on Nimbus but well under it on Lighthouse and Prysm, and Besu the reverse" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNjAwIDEwNDAiIGZvbnQtZmFtaWx5PSItYXBwbGUtc3lzdGVtLCAnU2Vnb2UgVUknLCBSb2JvdG8sIEhlbHZldGljYSwgQXJpYWwsIHNhbnMtc2VyaWYiPgogIDxkZWZzPgogICAgPHBhdHRlcm4gaWQ9ImdyaWQtY2MiIHdpZHRoPSI4MCIgaGVpZ2h0PSI4MCIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CiAgICAgIDxwYXRoIGQ9Ik0gODAgMCBMIDAgMCAwIDgwIiBmaWxsPSJub25lIiBzdHJva2U9IiMxYzI2NTQiIHN0cm9rZS13aWR0aD0iMC41Ii8+CiAgICA8L3BhdHRlcm4+CiAgPC9kZWZzPgoKICA8cmVjdCB3aWR0aD0iMTYwMCIgaGVpZ2h0PSIxMDQwIiBmaWxsPSIjMGUxNTMwIi8+CiAgPHJlY3Qgd2lkdGg9IjE2MDAiIGhlaWdodD0iMTA0MCIgZmlsbD0idXJsKCNncmlkLWNjKSIvPgogIDxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxNjAwIiBoZWlnaHQ9IjE0IiBmaWxsPSIjNTA0NmU1Ii8+CgogIDx0ZXh0IHg9IjEwMCIgeT0iMTAwIiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjI4IiBmb250LXdlaWdodD0iNjAwIj5TdGVyZXVtTGFiczwvdGV4dD4KICA8dGV4dCB4PSIxNTAwIiB5PSIxMDAiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMjAiIHRleHQtYW5jaG9yPSJlbmQiPjctZGF5IFA5OSDCtyAzIENDIG9ic2VydmVyczwvdGV4dD4KCiAgPHRleHQgeD0iODAwIiB5PSIxODUiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iNTAiIGZvbnQtd2VpZ2h0PSI3MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGxldHRlci1zcGFjaW5nPSItMS4yIj5TYW1lIEVDLCBkaWZmZXJlbnQgY29uc2Vuc3VzIGNsaWVudCwgZGlmZmVyZW50IHZlcmRpY3Q8L3RleHQ+CiAgPHRleHQgeD0iODAwIiB5PSIyMzIiIGZpbGw9IiNjNGI1ZmQiIGZvbnQtc2l6ZT0iMjQiIHRleHQtYW5jaG9yPSJtaWRkbGUiPlA5OSBlbmdpbmVfbmV3UGF5bG9hZCBwZXIgRUMsIG1lYXN1cmVkIGZyb20gZWFjaCBDQy4gRGFzaGVkIGxpbmUgPSA0IHMgZGVhZGxpbmUuPC90ZXh0PgoKICA8IS0tIGxlZ2VuZCAtLT4KICA8cmVjdCB4PSI0NzAiIHk9IjI3NiIgd2lkdGg9IjI2IiBoZWlnaHQ9IjE4IiByeD0iMyIgZmlsbD0iIzIyZDNlZSIvPgogIDx0ZXh0IHg9IjUwNCIgeT0iMjkxIiBmaWxsPSIjY2JkNWUxIiBmb250LXNpemU9IjE5Ij5OaW1idXM8L3RleHQ+CiAgPHJlY3QgeD0iNjQwIiB5PSIyNzYiIHdpZHRoPSIyNiIgaGVpZ2h0PSIxOCIgcng9IjMiIGZpbGw9IiNhNzhiZmEiLz4KICA8dGV4dCB4PSI2NzQiIHk9IjI5MSIgZmlsbD0iI2NiZDVlMSIgZm9udC1zaXplPSIxOSI+TGlnaHRob3VzZTwvdGV4dD4KICA8cmVjdCB4PSI4NTAiIHk9IjI3NiIgd2lkdGg9IjI2IiBoZWlnaHQ9IjE4IiByeD0iMyIgZmlsbD0iI2ZiYmYyNCIvPgogIDx0ZXh0IHg9Ijg4NCIgeT0iMjkxIiBmaWxsPSIjY2JkNWUxIiBmb250LXNpemU9IjE5Ij5QcnlzbTwvdGV4dD4KCiAgPCEtLSA0cyBkZWFkbGluZSBsaW5lOiB4ID0gMzAwICsgNCoyMDAgPSAxMTAwIC0tPgogIDxsaW5lIHgxPSIxMTAwIiB5MT0iMzQ1IiB4Mj0iMTEwMCIgeTI9IjkxNSIgc3Ryb2tlPSIjZjg3MTcxIiBzdHJva2Utd2lkdGg9IjMiIHN0cm9rZS1kYXNoYXJyYXk9IjggNiIvPgogIDx0ZXh0IHg9IjExMDAiIHk9IjMzOCIgZmlsbD0iI2ZjYTVhNSIgZm9udC1zaXplPSIxOSIgZm9udC13ZWlnaHQ9IjYwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+NCBzIGRlYWRsaW5lPC90ZXh0PgoKICA8IS0tIGdyb3Vwczogc2NhbGUgMjAwIHB4L3MsIHgwPTMwMC4gTmltYnVzL0xpZ2h0aG91c2UvUHJ5c20gYmFycywgaD0yNCBwaXRjaCAyOCAtLT4KICA8IS0tIEJlc3UgLS0+CiAgPHRleHQgeD0iNjAiIHk9IjQwNSIgZmlsbD0iI2UyZThmMCIgZm9udC1zaXplPSIyMyIgZm9udC13ZWlnaHQ9IjYwMCI+QmVzdTwvdGV4dD4KICA8cmVjdCB4PSIzMDAiIHk9IjM2MCIgd2lkdGg9IjIxNCIgaGVpZ2h0PSIyNCIgcng9IjMiIGZpbGw9IiMyMmQzZWUiLz48dGV4dCB4PSI1MjQiIHk9IjM3OCIgZmlsbD0iI2NiZDVlMSIgZm9udC1zaXplPSIxOCI+MS4wNyBzPC90ZXh0PgogIDxyZWN0IHg9IjMwMCIgeT0iMzg4IiB3aWR0aD0iOTcyIiBoZWlnaHQ9IjI0IiByeD0iMyIgZmlsbD0iI2E3OGJmYSIvPjx0ZXh0IHg9IjEyODIiIHk9IjQwNiIgZmlsbD0iI2NiZDVlMSIgZm9udC1zaXplPSIxOCI+NC44NiBzPC90ZXh0PgogIDxyZWN0IHg9IjMwMCIgeT0iNDE2IiB3aWR0aD0iNzgyIiBoZWlnaHQ9IjI0IiByeD0iMyIgZmlsbD0iI2ZiYmYyNCIvPjx0ZXh0IHg9IjEwOTIiIHk9IjQzNCIgZmlsbD0iI2NiZDVlMSIgZm9udC1zaXplPSIxOCI+My45MSBzPC90ZXh0PgoKICA8IS0tIEVyaWdvbiAtLT4KICA8dGV4dCB4PSI2MCIgeT0iNTIxIiBmaWxsPSIjZTJlOGYwIiBmb250LXNpemU9IjIzIiBmb250LXdlaWdodD0iNjAwIj5Fcmlnb248L3RleHQ+CiAgPHJlY3QgeD0iMzAwIiB5PSI0NzYiIHdpZHRoPSI0MzgiIGhlaWdodD0iMjQiIHJ4PSIzIiBmaWxsPSIjMjJkM2VlIi8+PHRleHQgeD0iNzQ4IiB5PSI0OTQiIGZpbGw9IiNjYmQ1ZTEiIGZvbnQtc2l6ZT0iMTgiPjIuMTkgczwvdGV4dD4KICA8dGV4dCB4PSIzMTAiIHk9IjUyMiIgZmlsbD0iIzk0YTNiOCIgZm9udC1zaXplPSIxOCIgZm9udC1zdHlsZT0iaXRhbGljIj5MaWdodGhvdXNlOiBuL2E8L3RleHQ+CiAgPHJlY3QgeD0iMzAwIiB5PSI1MzIiIHdpZHRoPSI2OTgiIGhlaWdodD0iMjQiIHJ4PSIzIiBmaWxsPSIjZmJiZjI0Ii8+PHRleHQgeD0iMTAwOCIgeT0iNTUwIiBmaWxsPSIjY2JkNWUxIiBmb250LXNpemU9IjE4Ij4zLjQ5IHM8L3RleHQ+CgogIDwhLS0gTmV0aGVybWluZCAtLT4KICA8dGV4dCB4PSI2MCIgeT0iNjM3IiBmaWxsPSIjZTJlOGYwIiBmb250LXNpemU9IjIzIiBmb250LXdlaWdodD0iNjAwIj5OZXRoZXJtaW5kPC90ZXh0PgogIDxyZWN0IHg9IjMwMCIgeT0iNTkyIiB3aWR0aD0iODg4IiBoZWlnaHQ9IjI0IiByeD0iMyIgZmlsbD0iIzIyZDNlZSIvPjx0ZXh0IHg9IjExOTgiIHk9IjYxMCIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIxOCIgZm9udC13ZWlnaHQ9IjYwMCI+NC40NCBzPC90ZXh0PgogIDxyZWN0IHg9IjMwMCIgeT0iNjIwIiB3aWR0aD0iMjgwIiBoZWlnaHQ9IjI0IiByeD0iMyIgZmlsbD0iI2E3OGJmYSIvPjx0ZXh0IHg9IjU5MCIgeT0iNjM4IiBmaWxsPSIjY2JkNWUxIiBmb250LXNpemU9IjE4Ij4xLjQwIHM8L3RleHQ+CiAgPHJlY3QgeD0iMzAwIiB5PSI2NDgiIHdpZHRoPSIyMTAiIGhlaWdodD0iMjQiIHJ4PSIzIiBmaWxsPSIjZmJiZjI0Ii8+PHRleHQgeD0iNTIwIiB5PSI2NjYiIGZpbGw9IiNjYmQ1ZTEiIGZvbnQtc2l6ZT0iMTgiPjEuMDUgczwvdGV4dD4KCiAgPCEtLSBHZXRoIC0tPgogIDx0ZXh0IHg9IjYwIiB5PSI3NTMiIGZpbGw9IiNlMmU4ZjAiIGZvbnQtc2l6ZT0iMjMiIGZvbnQtd2VpZ2h0PSI2MDAiPkdldGg8L3RleHQ+CiAgPHJlY3QgeD0iMzAwIiB5PSI3MDgiIHdpZHRoPSI5MzQiIGhlaWdodD0iMjQiIHJ4PSIzIiBmaWxsPSIjMjJkM2VlIi8+PHRleHQgeD0iMTI0NCIgeT0iNzI2IiBmaWxsPSIjY2JkNWUxIiBmb250LXNpemU9IjE4Ij40LjY3IHM8L3RleHQ+CiAgPHJlY3QgeD0iMzAwIiB5PSI3MzYiIHdpZHRoPSI5MjYiIGhlaWdodD0iMjQiIHJ4PSIzIiBmaWxsPSIjYTc4YmZhIi8+PHRleHQgeD0iMTIzNiIgeT0iNzU0IiBmaWxsPSIjY2JkNWUxIiBmb250LXNpemU9IjE4Ij40LjYzIHM8L3RleHQ+CiAgPHJlY3QgeD0iMzAwIiB5PSI3NjQiIHdpZHRoPSI2ODIiIGhlaWdodD0iMjQiIHJ4PSIzIiBmaWxsPSIjZmJiZjI0Ii8+PHRleHQgeD0iOTkyIiB5PSI3ODIiIGZpbGw9IiNjYmQ1ZTEiIGZvbnQtc2l6ZT0iMTgiPjMuNDEgczwvdGV4dD4KCiAgPCEtLSBFdGhyZXggLS0+CiAgPHRleHQgeD0iNjAiIHk9Ijg2OSIgZmlsbD0iI2UyZThmMCIgZm9udC1zaXplPSIyMyIgZm9udC13ZWlnaHQ9IjYwMCI+RXRocmV4PC90ZXh0PgogIDxyZWN0IHg9IjMwMCIgeT0iODI0IiB3aWR0aD0iMTAwMCIgaGVpZ2h0PSIyNCIgcng9IjMiIGZpbGw9IiMyMmQzZWUiLz48dGV4dCB4PSIxMzEwIiB5PSI4NDIiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMTgiIGZvbnQtd2VpZ2h0PSI2MDAiPuKJpTUuMDAgczwvdGV4dD4KICA8cmVjdCB4PSIzMDAiIHk9Ijg1MiIgd2lkdGg9Ijg5OCIgaGVpZ2h0PSIyNCIgcng9IjMiIGZpbGw9IiNhNzhiZmEiLz48dGV4dCB4PSIxMjA4IiB5PSI4NzAiIGZpbGw9IiNjYmQ1ZTEiIGZvbnQtc2l6ZT0iMTgiPjQuNDkgczwvdGV4dD4KICA8cmVjdCB4PSIzMDAiIHk9Ijg4MCIgd2lkdGg9IjcxMCIgaGVpZ2h0PSIyNCIgcng9IjMiIGZpbGw9IiNmYmJmMjQiLz48dGV4dCB4PSIxMDIwIiB5PSI4OTgiIGZpbGw9IiNjYmQ1ZTEiIGZvbnQtc2l6ZT0iMTgiPjMuNTUgczwvdGV4dD4KCiAgPHJlY3QgeD0iMTAwIiB5PSI5NTAiIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjQ4IiByeD0iNCIgZmlsbD0iIzFlMjkzYiIgc3Ryb2tlPSIjMzM0MTU1IiBzdHJva2Utd2lkdGg9IjEiLz4KICA8dGV4dCB4PSI4MDAiIHk9Ijk4MCIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxOSIgdGV4dC1hbmNob3I9Im1pZGRsZSI+TmV0aGVybWluZCBpcyB3b3JzdCBvbiBOaW1idXMgYnV0IGZpbmUgb24gTGlnaHRob3VzZS9QcnlzbTsgQmVzdSBpcyB0aGUgcmV2ZXJzZS4gUmV0aCBleGNsdWRlZCAoc3RpbGwgc3luY2luZykuPC90ZXh0PgoKICA8dGV4dCB4PSIxMDAiIHk9IjEwMjgiIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMTYiPsKpIFJvY2tMb2dpYyBHbWJIPC90ZXh0PgogIDx0ZXh0IHg9IjE1MDAiIHk9IjEwMjgiIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMTYiIHRleHQtYW5jaG9yPSJlbmQiPmRvY3Muc3RlcmV1bWxhYnMuY29tPC90ZXh0Pgo8L3N2Zz4K" width="1600" height="1040" class="img_ev3q"></p>
<p><em>The same EC lands on opposite sides of the 4 s line depending on the CC watching. Nethermind breaches on Nimbus only; Besu breaches on Lighthouse.</em></p>
<p>Across the synced clients:</p>
<ul>
<li class=""><strong>Nethermind</strong>: 4.44 s on Nimbus, ~1 s on Lighthouse and Prysm. Nimbus calls newPayload later in the slot, into Nethermind's in-memory pruning window between blocks.</li>
<li class=""><strong>Besu</strong>: 1.07 s on Nimbus, ~4 to 5 s on Lighthouse. The Bonsai path meets the Lighthouse calling pattern differently.</li>
<li class=""><strong>Geth</strong>: over 3.4 s on every CC. Its PBSS commit cost lands on the engine thread whenever the call arrives.</li>
<li class=""><strong>Ethrex</strong>: 3.55 s to ≥5.00 s on every CC. Different cause (slow block validation, not pruning), same outcome for duty timing.</li>
</ul>
<p>So "is my EC fast enough?" depends on the pairing, not the EC alone. The rule: if any CC↔EC pair holds a P99 above 4 s, that pair is the one to investigate for late sync-committee messages. Re-measure with your own CC's histogram first. Latency that swings this much by consensus client is a recurring pattern on this fleet; we saw the same shape in <a class="" href="https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients">blob verification latency across consensus clients</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-nethermind-ships-this-trade-off-the-v1371-prs">Why Nethermind ships this trade-off (the v1.37.1 PRs)<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#why-nethermind-ships-this-trade-off-the-v1371-prs" class="hash-link" aria-label="Direct link to Why Nethermind ships this trade-off (the v1.37.1 PRs)" title="Direct link to Why Nethermind ships this trade-off (the v1.37.1 PRs)" translate="no">​</a></h3>
<p>Nethermind 1.37.2 inherited two 1.37.1 changes that trade engine-thread serialization for lower queue latency:</p>
<ol>
<li class=""><strong><a href="https://github.com/NethermindEth/nethermind/pull/10479" target="_blank" rel="noopener noreferrer" class="">nethermind#10479</a>, "Run newPayload inline"</strong> (Feb 2026). Enables <code>AllowSynchronousContinuations</code>, so <code>newPayload</code> runs on the engine thread when the queue is empty. It saves a context switch, but any in-flight prune on that thread now extends <code>newPayload</code> directly. This is why a Nethermind behind a CC that calls at the wrong moment hits 4 to 7 s spikes.</li>
<li class=""><strong><a href="https://github.com/NethermindEth/nethermind/pull/10247" target="_blank" rel="noopener noreferrer" class="">nethermind#10247</a>, "Bump default pruning cache by 512MB"</strong> (Jan 2026). <code>Pruning.CacheMb</code> 1280 → 1792, <code>Pruning.DirtyCacheMb</code> 1024 → 1536. The PR's own note: <em>"does take a bunch longer; but also is between blocks so should be ok."</em> On our fleet that assumption breaks; the longer cycle does not always finish between blocks under load.</li>
<li class=""><strong><a href="https://github.com/NethermindEth/nethermind/pull/10227" target="_blank" rel="noopener noreferrer" class="">nethermind#10227</a></strong> added the two knobs operators now need: <code>Pruning.PruneDelayMilliseconds</code> (default 75 ms, gap between prune iterations) and <code>Merge.PostBlockGcDelayMs</code> (default <code>SecondsPerSlot/8 = 1500 ms</code>).</li>
</ol>
<p>Fleet evidence: <code>nethermind_pruning_time</code> baselines at ~700 ms with regular spikes to <strong>4,000 to 6,300 ms</strong>, and <code>nethermind_pruning_cutoff_blocknumber = 0</code> for the whole window. No deep prune ran; every spike is the in-memory pruner alone. The Nethermind pairing turning up as the slow one is a repeat finding on this fleet: our <a class="" href="https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources">Teku version comparison</a> flagged persistently elevated block-import delays on the Teku + Nethermind pairing across three releases, so this is not purely a Nimbus artifact.</p>
<p><img decoding="async" loading="lazy" alt="Line chart of nethermind_pruning_time over 24 hours on one host: a flat ~700 ms baseline with intermittent spikes, the largest reaching 5.06 seconds, well above the dashed 4-second deadline line" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNjAwIDkwMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPGRlZnM+CiAgICA8cGF0dGVybiBpZD0iZ3JpZC1wdCIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBwYXR0ZXJuVW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHBhdGggZD0iTSA4MCAwIEwgMCAwIDAgODAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIwLjUiLz4KICAgIDwvcGF0dGVybj4KICA8L2RlZnM+CgogIDxyZWN0IHdpZHRoPSIxNjAwIiBoZWlnaHQ9IjkwMCIgZmlsbD0iIzBlMTUzMCIvPgogIDxyZWN0IHdpZHRoPSIxNjAwIiBoZWlnaHQ9IjkwMCIgZmlsbD0idXJsKCNncmlkLXB0KSIvPgogIDxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxNjAwIiBoZWlnaHQ9IjE0IiBmaWxsPSIjNTA0NmU1Ii8+CgogIDx0ZXh0IHg9IjEwMCIgeT0iMTAwIiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjI4IiBmb250LXdlaWdodD0iNjAwIj5TdGVyZXVtTGFiczwvdGV4dD4KICA8dGV4dCB4PSIxNTAwIiB5PSIxMDAiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMjAiIHRleHQtYW5jaG9yPSJlbmQiPm5ldGhlcm1pbmRfcHJ1bmluZ190aW1lIMK3IDEgaG9zdCDCtyAyNCBoPC90ZXh0PgoKICA8dGV4dCB4PSI4MDAiIHk9IjE3MCIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSI0OCIgZm9udC13ZWlnaHQ9IjcwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgbGV0dGVyLXNwYWNpbmc9Ii0xLjIiPk5ldGhlcm1pbmQgcHJ1bmUgY3ljbGVzIHNwaWtlIHBhc3QgdGhlIGRlYWRsaW5lPC90ZXh0PgogIDx0ZXh0IHg9IjgwMCIgeT0iMjE0IiBmaWxsPSIjYzRiNWZkIiBmb250LXNpemU9IjIzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5Nb3N0IGN5Y2xlcyBydW4gfjcwMCBtczsgYSBmZXcgYmxvdyBwYXN0IDQgcywgc3RyYWlnaHQgdGhyb3VnaCB0aGUgc3luYy1jb21taXR0ZWUgYnVkZ2V0LjwvdGV4dD4KCiAgPCEtLSB5IGdyaWRsaW5lcyArIGxhYmVsczogMC4uNSBzIC0tPgogIDxnIHN0cm9rZT0iIzI0MzA1NiIgc3Ryb2tlLXdpZHRoPSIxIj4KICAgIDxsaW5lIHgxPSIyMDAiIHkxPSI3NjAiIHgyPSIxNTIwIiB5Mj0iNzYwIi8+CiAgICA8bGluZSB4MT0iMjAwIiB5MT0iNjYyIiB4Mj0iMTUyMCIgeTI9IjY2MiIvPgogICAgPGxpbmUgeDE9IjIwMCIgeTE9IjU2NCIgeDI9IjE1MjAiIHkyPSI1NjQiLz4KICAgIDxsaW5lIHgxPSIyMDAiIHkxPSI0NjUiIHgyPSIxNTIwIiB5Mj0iNDY1Ii8+CiAgICA8bGluZSB4MT0iMjAwIiB5MT0iMjY5IiB4Mj0iMTUyMCIgeTI9IjI2OSIvPgogIDwvZz4KICA8ZyBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE4IiB0ZXh0LWFuY2hvcj0iZW5kIj4KICAgIDx0ZXh0IHg9IjE4MCIgeT0iNzY2Ij4wPC90ZXh0PgogICAgPHRleHQgeD0iMTgwIiB5PSI2NjgiPjEgczwvdGV4dD4KICAgIDx0ZXh0IHg9IjE4MCIgeT0iNTcwIj4yIHM8L3RleHQ+CiAgICA8dGV4dCB4PSIxODAiIHk9IjQ3MSI+MyBzPC90ZXh0PgogICAgPHRleHQgeD0iMTgwIiB5PSIzNzMiPjQgczwvdGV4dD4KICAgIDx0ZXh0IHg9IjE4MCIgeT0iMjc1Ij41IHM8L3RleHQ+CiAgPC9nPgoKICA8IS0tIDQgcyBkZWFkbGluZSAtLT4KICA8bGluZSB4MT0iMjAwIiB5MT0iMzY3IiB4Mj0iMTUyMCIgeTI9IjM2NyIgc3Ryb2tlPSIjZjg3MTcxIiBzdHJva2Utd2lkdGg9IjIuNSIgc3Ryb2tlLWRhc2hhcnJheT0iOCA2Ii8+CiAgPHRleHQgeD0iMTUxNiIgeT0iMzU4IiBmaWxsPSIjZmNhNWE1IiBmb250LXNpemU9IjE5IiBmb250LXdlaWdodD0iNjAwIiB0ZXh0LWFuY2hvcj0iZW5kIj40IHMgc3luYy1jb21taXR0ZWUgZGVhZGxpbmU8L3RleHQ+CgogIDwhLS0gc2VyaWVzIC0tPgogIDxwb2x5bGluZSBmaWxsPSJub25lIiBzdHJva2U9IiM3Mzg0ZjUiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBwb2ludHM9IjIwMCw2OTQgMjM1LDY4OSAyNjksNjgzIDMwNCw2ODEgMzM5LDY3NCAzNzQsNjgxIDQwOCw2NzcgNDQzLDY2NCA0NzgsNjcwIDUxMyw2ODMgNTQ3LDY3NyA1ODIsNjcyIDYxNyw2ODAgNjUyLDY4OCA2ODYsNjI0IDcyMSw2NjkgNzU2LDU3MyA3OTEsNjk3IDgyNSw2OTUgODYwLDcwMSA4OTUsNjk4IDkyOSw2ODggOTY0LDcwNSA5OTksNjk5IDEwMzQsNjkxIDEwNjgsNjg5IDExMDMsNjY0IDExMzgsNjk4IDExNzMsNjc1IDEyMDcsNTcwIDEyNDIsNjM5IDEyNzcsNTQ4IDEzMTIsNTgzIDEzNDYsMjYzIDEzODEsNjc3IDE0MTYsNjc2IDE0NTEsNjEwIDE0ODUsNjc3IDE1MjAsNjgzIi8+CgogIDwhLS0gcGVhayBjYWxsb3V0IC0tPgogIDxjaXJjbGUgY3g9IjEzNDYiIGN5PSIyNjMiIHI9IjYiIGZpbGw9IiNmODcxNzEiLz4KICA8dGV4dCB4PSIxMzQ2IiB5PSIyNDUiIGZpbGw9IiNmY2E1YTUiIGZvbnQtc2l6ZT0iMjAiIGZvbnQtd2VpZ2h0PSI3MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPjUuMDYgczwvdGV4dD4KICA8dGV4dCB4PSIxMzQ2IiB5PSIyMjUiIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMTYiIHRleHQtYW5jaG9yPSJtaWRkbGUiPm9uZSBwcnVuZSBjeWNsZTwvdGV4dD4KCiAgPCEtLSBiYXNlbGluZSBub3RlIC0tPgogIDx0ZXh0IHg9IjI1MCIgeT0iNzMwIiBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE3IiBmb250LXN0eWxlPSJpdGFsaWMiPmJhc2VsaW5lIH42MDDigJM5MDAgbXM8L3RleHQ+CgogIDwhLS0geCBsYWJlbHMgLS0+CiAgPGcgZmlsbD0iIzk0YTNiOCIgZm9udC1zaXplPSIxOCI+CiAgICA8dGV4dCB4PSIyMDAiIHk9Ijc4OCI+MjQgaCBhZ288L3RleHQ+CiAgICA8dGV4dCB4PSI4NjAiIHk9Ijc4OCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+MTIgaCBhZ288L3RleHQ+CiAgICA8dGV4dCB4PSIxNTIwIiB5PSI3ODgiIHRleHQtYW5jaG9yPSJlbmQiPm5vdzwvdGV4dD4KICA8L2c+CgogIDx0ZXh0IHg9IjgwMCIgeT0iODQ1IiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5Mb2Rlc3Rhci1wYWlyZWQgTmV0aGVybWluZCBob3N0LiBUaGUgaW4tbWVtb3J5IHBydW5lciBhbG9uZSBkcml2ZXMgZXZlcnkgc3Bpa2UgKG5vIGRlZXAgcHJ1bmUgcmFuKS48L3RleHQ+CgogIDx0ZXh0IHg9IjEwMCIgeT0iODgyIiBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE1Ij7CqSBSb2NrTG9naWMgR21iSDwvdGV4dD4KICA8dGV4dCB4PSIxNTAwIiB5PSI4ODIiIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMTUiIHRleHQtYW5jaG9yPSJlbmQiPmRvY3Muc3RlcmV1bWxhYnMuY29tPC90ZXh0Pgo8L3N2Zz4K" width="1600" height="900" class="img_ev3q"></p>
<p><em>24 h on one Nethermind host. The baseline is harmless; the spikes are not. The 5.06 s cycle alone overruns the slot budget, and a newPayload landing in that window inherits the delay.</em></p>
<p>Open Nethermind tracker items:</p>
<ul>
<li class=""><a href="https://github.com/NethermindEth/nethermind/issues/10557" target="_blank" rel="noopener noreferrer" class="">nethermind#10557</a> (open, stability): production validator infrastructure issue for this pattern.</li>
<li class=""><a href="https://github.com/NethermindEth/nethermind/issues/6893" target="_blank" rel="noopener noreferrer" class="">nethermind#6893</a> (open): FCU/newPayload timeouts with Lighthouse after restart.</li>
<li class=""><a href="https://github.com/NethermindEth/nethermind/issues/8433" target="_blank" rel="noopener noreferrer" class="">nethermind#8433</a> (open since 2025-03): memory-config recommendations, no conclusion.</li>
<li class=""><a href="https://github.com/NethermindEth/nethermind/issues/9149" target="_blank" rel="noopener noreferrer" class="">nethermind#9149</a> (closed via <a href="https://github.com/NethermindEth/nethermind/pull/9588" target="_blank" rel="noopener noreferrer" class="">PR #9588</a>): proposed pausing in-memory pruning; the merged PR only marks finalized blocks, it does not pause.</li>
</ul>
<p>In-flight PRs that may help in a later release: <a href="https://github.com/NethermindEth/nethermind/pull/11539" target="_blank" rel="noopener noreferrer" class="">nethermind#11539</a> (hot-path allocations), <a href="https://github.com/NethermindEth/nethermind/pull/10952" target="_blank" rel="noopener noreferrer" class="">nethermind#10952</a> (PersistenceManager prune leak), <a href="https://github.com/NethermindEth/nethermind/pull/11636" target="_blank" rel="noopener noreferrer" class="">nethermind#11636</a> (double execution in <code>newPayloadWithWitness</code>).</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-each-client-runs-pruning-relative-to-the-engine-thread">Where each client runs pruning relative to the engine thread<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#where-each-client-runs-pruning-relative-to-the-engine-thread" class="hash-link" aria-label="Direct link to Where each client runs pruning relative to the engine thread" title="Direct link to Where each client runs pruning relative to the engine thread" translate="no">​</a></h3>
<table><thead><tr><th>EC</th><th>Where pruning runs</th><th>Engine-thread impact</th><th style="text-align:right">Design rank</th></tr></thead><tbody><tr><td>Reth</td><td>Persistence task gated by explicit backpressure</td><td>None unless backpressure trips (<strong>unmeasured here, hosts unsynced</strong>)</td><td style="text-align:right">1 (design)</td></tr><tr><td>Besu</td><td>Bonsai trie-log pruning in a separate process</td><td>None on engine path</td><td style="text-align:right">2</td></tr><tr><td>Erigon</td><td>Own stage in the execution goroutine</td><td>Bounded, ~2 s</td><td style="text-align:right">3</td></tr><tr><td>Geth</td><td>PBSS state-history writes on engine path</td><td>Direct, spike-prone under commit pressure</td><td style="text-align:right">4</td></tr><tr><td>Nethermind</td><td>In-memory trie prune, optionally inline newPayload (1.37.1)</td><td>Direct, blocks during prune iterations</td><td style="text-align:right">5</td></tr><tr><td>Ethrex</td><td>No state-trie pruning shipped</td><td>n/a (different problem)</td><td style="text-align:right">n/a</td></tr></tbody></table>
<p>Sources: Reth's backpressure is a first-class metric (<a href="https://github.com/paradigmxyz/reth/issues/3428" target="_blank" rel="noopener noreferrer" class=""><code>reth_consensus_engine_beacon_backpressure_active</code></a>) with a documented <code>--engine.persistence-backpressure-threshold</code> knob. Besu's separate-process choice is in <a href="https://github.com/hyperledger/besu/issues/4476" target="_blank" rel="noopener noreferrer" class="">besu#4476</a>, with <a href="https://github.com/hyperledger/besu/pull/4409" target="_blank" rel="noopener noreferrer" class="">PR #4409</a> dropping p95 block processing from 2.98 s to 0.81 s. Erigon's bounded stage is what remained after <a href="https://github.com/erigontech/erigon/issues/6584" target="_blank" rel="noopener noreferrer" class="">erigon#6584</a> closed as not-planned. Geth's pattern is <a href="https://github.com/ethereum/go-ethereum/issues/28317" target="_blank" rel="noopener noreferrer" class="">geth#28317</a>.</p>
<p>This is a <em>design</em> ranking, not a measured leaderboard: the cross-CC table shows the measured order moves with the observer, and Reth's rank-1 design is untested because its hosts never synced.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-an-operator-can-tune-today">What an operator can tune today<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#what-an-operator-can-tune-today" class="hash-link" aria-label="Direct link to What an operator can tune today" title="Direct link to What an operator can tune today" translate="no">​</a></h3>
<p>Starting points to test on a canary node, not blind production changes. We applied the Nethermind set on our own nodes; the rest come from each client's docs and source, linked inline so you can check the exact key names and defaults yourself.</p>
<p><strong>Nethermind 1.37.2</strong> has the highest measured impact, so start here. The lever is making each prune iteration yield to the engine thread, not growing the cache:</p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini 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"># Pruning</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">PruneDelayMilliseconds = 150   # default 75; the main lever, more yield to the engine thread</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">DirtyCacheMb = 1280            # default 1536; smaller dirty cache = shorter prune cycles</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"># Merge</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">PostBlockGcDelayMs = 900       # default SecondsPerSlot/8 = 1500</span><br></span></code></pre></div></div>
<p><code>Pruning.PruneDelayMilliseconds</code> and <code>Merge.PostBlockGcDelayMs</code> were added in <a href="https://github.com/NethermindEth/nethermind/pull/10227" target="_blank" rel="noopener noreferrer" class="">nethermind#10227</a> (defaults 75 ms and <code>SecondsPerSlot/8</code>); the <code>Pruning.CacheMb</code> 1280→1792 and <code>Pruning.DirtyCacheMb</code> 1024→1536 default bumps are <a href="https://github.com/NethermindEth/nethermind/pull/10247" target="_blank" rel="noopener noreferrer" class="">nethermind#10247</a>. <strong>Do not raise <code>Pruning.CacheMb</code> to fix the latency:</strong> a bigger cache makes each prune cycle take longer (that PR's own note: <em>"does take a bunch longer"</em>), the opposite of what you want when the prune collides with <code>newPayload</code>. Shorter, more frequent iterations with a higher <code>PruneDelayMilliseconds</code> keep the engine thread responsive. These keys live in Nethermind's JSON/<code>.cfg</code> config or <code>--Pruning.PruneDelayMilliseconds</code>-style flags, not YAML. Validate against your own P99 first.</p>
<p><strong>Geth v1.17.x</strong> (<a href="https://geth.ethereum.org/docs/fundamentals/command-line-options" target="_blank" rel="noopener noreferrer" class="">command-line options</a>): <code>--cache 8192</code> (default 4096) if memory allows, and raise <code>--cache.trie</code> (default 15, the percentage of <code>--cache</code> given to the trie). Do not reach for <code>--gcmode archive</code> on a validator: it stops pruning but turns the node into a multi-TB growing archive, a different deployment, not a knob. Ancient-store growth is bounded separately by <code>--history.transactions</code> and <code>--history.logs</code> (both default 2,350,000 blocks), and path-mode state by <code>--history.state</code> (default 90,000).</p>
<p><strong>Reth v2.2.0</strong>: no synced host here, so no measured advice. By design it gates pruning behind engine backpressure (<a href="https://reth.rs/cli/reth/node/" target="_blank" rel="noopener noreferrer" class=""><code>--engine.persistence-backpressure-threshold</code></a>, default 16, introduced in Reth 2.0); confirm against your own synced node's P99.</p>
<p><strong>Besu 26.5.0</strong> (<a href="https://besu.hyperledger.org/public-networks/how-to/bonsai-limit-trie-logs" target="_blank" rel="noopener noreferrer" class="">limit-trie-logs docs</a>): keep <code>--bonsai-limit-trie-logs-enabled=true</code> (default in 26.5+); the prune batch is <code>--bonsai-trie-logs-pruning-window-size</code> (default 30000). Besu was the slowest from the Lighthouse observer (~4.9 s), so test against your actual CC.</p>
<p><strong>Erigon v3.4.x</strong> (<a href="https://docs.erigon.tech/advanced/options" target="_blank" rel="noopener noreferrer" class="">options</a>): little to tune; accept the ~2 s baseline. <code>--prune.mode</code> defaults to <code>full</code>; <code>archive</code> does the opposite of saving disk (it keeps all state history), so only use it if you need archive data.</p>
<p><strong>Ethrex 13.0.0</strong>: not validator-grade in our measurements (≥3.5 s on every CC); track upstream and raise your CC's per-EL timeout if you must run it.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-sync-committee-duties-get-hit-before-attestations">Why sync-committee duties get hit before attestations<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#why-sync-committee-duties-get-hit-before-attestations" class="hash-link" aria-label="Direct link to Why sync-committee duties get hit before attestations" title="Direct link to Why sync-committee duties get hit before attestations" translate="no">​</a></h3>
<p>Both duties share the slot-start + ~4 s deadline. But an attestation has one slot of inclusion grace via the next aggregator, while a sync-committee message is aggregated into the next block's <code>sync_aggregate</code> and a late one misses that inclusion outright. So the same newPayload tail that dents attestation effectiveness dents sync-committee participation more, in percentage terms. That matches what we and other Nethermind operators see: sync-committee periods feel disproportionately bad during pruning windows, even when attestation effectiveness barely moves.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="cross-client-cheat-sheet">Cross-client cheat sheet<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#cross-client-cheat-sheet" class="hash-link" aria-label="Direct link to Cross-client cheat sheet" title="Direct link to Cross-client cheat sheet" translate="no">​</a></h2>
<p>By the question you are actually asking:</p>
<p><strong>How much disk does my EC use?</strong> Use <code>(node_filesystem_size_bytes − node_filesystem_avail_bytes)</code> on the datadir mount. The EC-internal size metrics all understate it (see methodology); node_exporter is the portable answer.</p>
<p><strong>Did my EC prune in the last 5 minutes?</strong> Yes on Erigon (<code>rate(prune_seconds_count[5m])</code>), Nethermind (<code>rate(nethermind_pruned_persisted_nodes_count[5m])</code>), Besu (<code>rate(besu_pruner_trie_log_pruned_from_queue_total[5m])</code>). No on Geth (no event counter), Reth (one event total, so any rate is noise), Ethrex (no metric).</p>
<p><strong>Has the deep/full prune fired?</strong> Only Nethermind tells you, via <code>nethermind_pruning_cutoff_blocknumber</code>. It is 0 here, so the deep prune has not run.</p>
<p><strong>Is this EC fast enough for my CC?</strong> Compute P99 <code>engine_newPayload</code> from your CC's histogram and compare to 4 s. The answer is per pairing, not per EC (see the latency section); re-measure on your own stack before trusting any ranking.</p>
<p><strong>Why did my pruner stop?</strong> Nethermind: <code>nethermind_state_db_in_pruning_writes</code> hits zero while disk grows. Erigon: <code>domain_prunable</code> rises while <code>domain_prune_size</code> stalls. Besu: the added-minus-pruned trie-log backlog grows. Geth: <code>pathdb_history_state_time</code> p99 climbs over hours. Reth and Ethrex: no usable signal, check the config or the disk.</p>
<p>This mirrors what the <a class="" href="https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients">reorg accounting post</a> found on the consensus side, where <code>beacon_reorgs_total</code> reads 0 on Lodestar and 6,011 on Prysm over 90 days, and what the <a class="" href="https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis">EC P2P peering deep dive</a> found in how differently each client reports the network. One shared concept, six instrumentation choices, and on Ethrex, silence.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-glamsterdam-history-expiry-will-change-ec-pruning">How Glamsterdam history expiry will change EC pruning<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#how-glamsterdam-history-expiry-will-change-ec-pruning" class="hash-link" aria-label="Direct link to How Glamsterdam history expiry will change EC pruning" title="Direct link to How Glamsterdam history expiry will change EC pruning" translate="no">​</a></h2>
<p><a href="https://eips.ethereum.org/EIPS/eip-4444" target="_blank" rel="noopener noreferrer" class="">EIP-4444</a> (history expiry) lets execution clients drop pre-expiry headers, bodies, and receipts instead of keeping them forever in ancient stores. Glamsterdam is the activation vehicle, in devnet stabilisation per <a href="https://blog.ethereum.org/2026/04/10/checkpoint-9" target="_blank" rel="noopener noreferrer" class="">the EF's April 2026 Checkpoint</a>, with no fixed mainnet slot yet. Two consequences for the numbers here:</p>
<ul>
<li class=""><strong>Geth's and Ethrex's footprints are mostly historical retention.</strong> Once operators flip on expiry, the ~1,688 GB Geth and ~598 GB Ethrex numbers should fall toward Erigon's ~509 GB. Read today's figures as the pre-expiry baseline.</li>
<li class=""><strong>The observability gap gets more expensive.</strong> A stalled pruner you can see (Erigon, Nethermind, Besu) is a quick fix; a stalled pruner on a client with no pruning metric (Ethrex) is invisible until the disk fills. If you cannot answer "is my EC pruning" today, you will not be able to answer "is it observing the post-expiry bounds" after the fork. The instrumentation needs to land first.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="frequently-asked-questions-about-ethereum-ec-pruning">Frequently asked questions about Ethereum EC pruning<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#frequently-asked-questions-about-ethereum-ec-pruning" class="hash-link" aria-label="Direct link to Frequently asked questions about Ethereum EC pruning" title="Direct link to Frequently asked questions about Ethereum EC pruning" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-is-erigons-datadir-33-smaller-than-geths-on-the-same-chain">Why is Erigon's datadir 3.3× smaller than Geth's on the same chain?<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#why-is-erigons-datadir-33-smaller-than-geths-on-the-same-chain" class="hash-link" aria-label="Direct link to Why is Erigon's datadir 3.3× smaller than Geth's on the same chain?" title="Direct link to Why is Erigon's datadir 3.3× smaller than Geth's on the same chain?" translate="no">​</a></h3>
<p>Storage architecture. Erigon prunes account, storage, and block-body history once fork-choice no longer needs it and keeps no ancient store. Geth path-mode keeps a bounded ~1.33 GB state journal plus a continuously growing ancient store. Both serve the same engine-API traffic; they just retain different amounts of history. EIP-4444 should narrow the gap.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-do-i-check-if-my-geth-path-mode-node-is-pruning-correctly">How do I check if my Geth path-mode node is pruning correctly?<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#how-do-i-check-if-my-geth-path-mode-node-is-pruning-correctly" class="hash-link" aria-label="Direct link to How do I check if my Geth path-mode node is pruning correctly?" title="Direct link to How do I check if my Geth path-mode node is pruning correctly?" translate="no">​</a></h3>
<p>Watch two metrics: <code>pathdb_history_state_bytes_data</code> should stay roughly flat at your <code>--history.state</code> window (default 90,000 blocks), and <code>pathdb_history_state_time</code> p99 should stay under ~2 ms. There is no prune-cycle counter; the bounded journal is the prune. Ancient-store growth is separate and bounded by <code>--history.transactions</code> and <code>--history.logs</code>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-does-netherminds-pruning_cutoff_blocknumber-stay-at-0">Why does Nethermind's <code>pruning_cutoff_blocknumber</code> stay at 0?<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#why-does-netherminds-pruning_cutoff_blocknumber-stay-at-0" class="hash-link" aria-label="Direct link to why-does-netherminds-pruning_cutoff_blocknumber-stay-at-0" title="Direct link to why-does-netherminds-pruning_cutoff_blocknumber-stay-at-0" translate="no">​</a></h3>
<p>On <code>PruningMode=Hybrid</code>, Nethermind runs a continuous in-memory pruner and only escalates to a disk-mode deep prune when needed. The deep prune has not been needed in our window, so the cutoff and <code>nethermind_deep_pruned_persisted_nodes_count</code> stay at 0 while the continuous pruner does the work at ~1,497 nodes/sec/host. It keeps the state DB flat on <code>nethermind_db_size</code>, but the full datadir still grows ~16 GB/week, so monitor root-FS for capacity.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-does-nethermind-miss-sync-committee-duties-during-pruning">Why does Nethermind miss sync-committee duties during pruning?<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#why-does-nethermind-miss-sync-committee-duties-during-pruning" class="hash-link" aria-label="Direct link to Why does Nethermind miss sync-committee duties during pruning?" title="Direct link to Why does Nethermind miss sync-committee duties during pruning?" translate="no">​</a></h3>
<p>Its 1.37.1 <a href="https://github.com/NethermindEth/nethermind/pull/10479" target="_blank" rel="noopener noreferrer" class="">inline-newPayload change</a> runs <code>engine_newPayload</code> on the engine thread, so an in-flight in-memory prune now serializes with it. <code>nethermind_pruning_time</code> spikes to 4 to 6 s, which pushes P99 past 4 s on Nimbus pairings. On Lighthouse and Prysm it stays ~1 s, so it is the Nimbus calling pattern meeting the inline path. Mitigate with <code>PruneDelayMilliseconds</code> up and <code>DirtyCacheMb</code> down (see the tuning section).</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-is-the-same-ec-fast-on-one-cc-and-slow-on-another">Why is the same EC fast on one CC and slow on another?<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#why-is-the-same-ec-fast-on-one-cc-and-slow-on-another" class="hash-link" aria-label="Direct link to Why is the same EC fast on one CC and slow on another?" title="Direct link to Why is the same EC fast on one CC and slow on another?" translate="no">​</a></h3>
<p>Each CC calls <code>notifyNewPayload</code> at a different point in the slot (Prysm early, Lighthouse mid, Nimbus late), so a CC that calls late meets more pruning contention. Nethermind is the clearest case: 4.44 s on Nimbus, ~1 s on Lighthouse and Prysm, same EC and load. The rule: if any CC↔EC pair holds a P99 above 4 s, investigate that pair, and measure with your own CC's histogram.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="is-reth-synced-in-this-comparison">Is Reth synced in this comparison?<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#is-reth-synced-in-this-comparison" class="hash-link" aria-label="Direct link to Is Reth synced in this comparison?" title="Direct link to Is Reth synced in this comparison?" translate="no">​</a></h3>
<p>No. Every Reth host is still in initial staged sync: the checkpoint sits ~70 to 130 k blocks behind the tip and has not advanced in 12 hours, every newPayload returns SYNCING, and the final pipeline stages are still at 0. So its disk figure is mid-sync state, its 0.23 s newPayload is the SYNCING return path, and its pruning is unmeasured. We will re-run once these hosts finish syncing.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-do-i-monitor-ethrex-pruning-without-prometheus-metrics">How do I monitor Ethrex pruning without Prometheus metrics?<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#how-do-i-monitor-ethrex-pruning-without-prometheus-metrics" class="hash-link" aria-label="Direct link to How do I monitor Ethrex pruning without Prometheus metrics?" title="Direct link to How do I monitor Ethrex pruning without Prometheus metrics?" translate="no">​</a></h3>
<p>Watch <code>datadir_size_bytes</code> and its 7-day delta. If it grows faster than mainnet block data implies (roughly 30 to 50 GB/month per client at current activity), investigate. There is no prune-event metric today; ask for one upstream, or write to <a href="mailto:contact@stereumlabs.com" target="_blank" rel="noopener noreferrer" class="">contact@stereumlabs.com</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="will-eip-4444-history-expiry-change-these-numbers">Will EIP-4444 history expiry change these numbers?<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#will-eip-4444-history-expiry-change-these-numbers" class="hash-link" aria-label="Direct link to Will EIP-4444 history expiry change these numbers?" title="Direct link to Will EIP-4444 history expiry change these numbers?" translate="no">​</a></h3>
<p>Yes, for the cumulative footprint. Geth's ~1,688 GB and Ethrex's ~598 GB are mostly historical block data that EIP-4444 lets clients drop; Erigon at ~509 GB already approximates the post-expiry state. (Reth is excluded; its hosts are still syncing.)</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="methodology">Methodology<a href="https://docs.stereumlabs.com/blog/ethereum-ec-pruning-behaviour#methodology" class="hash-link" aria-label="Direct link to Methodology" title="Direct link to Methodology" translate="no">​</a></h2>
<p>All queries ran against our <code>prometheus-cold</code> datasource over windows ending around 2026-05-28 12:00 UTC.</p>
<p>Per-EC root-FS used (the ground-truth for on-disk size), 7-day rolling average, and its 7-day net delta:</p>
<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 by (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_filesystem_size_bytes{mountpoint="/", fstype!="rootfs", role="ec"}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">     - node_filesystem_avail_bytes{mountpoint="/", fstype!="rootfs", role="ec"})[7d: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><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">avg by (ec_client) (</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  (node_filesystem_size_bytes{mountpoint="/", fstype!="rootfs", role="ec"}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   - node_filesystem_avail_bytes{mountpoint="/", fstype!="rootfs", role="ec"})</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">  (node_filesystem_size_bytes{mountpoint="/", fstype!="rootfs", role="ec"} offset 7d</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   - node_filesystem_avail_bytes{mountpoint="/", fstype!="rootfs", role="ec"} offset 7d)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">)</span><br></span></code></pre></div></div>
<p>Per-EC pruning-event rates, plus the Geth path-mode and Nethermind in-pruning signals:</p>
<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">sum by (ec_client) (rate(besu_pruner_trie_log_pruned_from_queue_total[7d])) * 86400</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">sum by (ec_client) (rate(nethermind_pruned_persisted_nodes_count[1h]))</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">sum by (ec_client, type) (increase(prune_seconds_count[7d]))</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">pathdb_gc_node_count</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">avg_over_time(nethermind_state_db_in_pruning_writes[7d])</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">nethermind_pruning_cutoff_blocknumber</span><br></span></code></pre></div></div>
<p>Reth sync-state check (confirming the hosts have not finished syncing, so their disk and newPayload numbers are mid-sync):</p>
<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">reth_blockchain_tree_canonical_chain_height</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">reth_consensus_engine_beacon_new_payload_valid</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">max by (instance) (reth_sync_checkpoint)          # vs chain_head_block; flat over 12h = no progress</span><br></span></code></pre></div></div>
<p>Every EC's sync state was cross-checked against its <strong>container logs</strong> in Elasticsearch (block-import lines such as Geth's <code>Imported new potential chain segment</code> or Besu's <code>Imported #…</code> for the synced clients, versus Reth's running <code>sync::stages</code> pipeline), not metrics alone, because a head-block metric can reflect the forkchoice head an EC is following optimistically while it is still syncing.</p>
<p>P99 <code>engine_newPayload</code> from each CC observer, 7-day rolling, and the Nethermind prune-cycle latency it tracks:</p>
<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"># Nimbus</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">histogram_quantile(0.99, sum by (cc_client, ec_client, le) (rate(engine_api_request_duration_seconds_bucket{request="newPayload"}[7d])))</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"># Lighthouse</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">histogram_quantile(0.99, sum by (cc_client, ec_client, le) (rate(execution_layer_request_times_bucket{method="new_payload"}[7d])))</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"># Prysm/Lodestar (Teku does not export this histogram in our window)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">histogram_quantile(0.99, sum by (cc_client, ec_client, le) (rate(new_payload_v1_latency_milliseconds_bucket[7d])))</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">nethermind_pruning_time</span><br></span></code></pre></div></div>
<p>Host counts, taken from <code>count by (ec_client) (count by (ec_client, instance) (up{role="ec", job!="node_exporter"}))</code>: Geth 13 (7 NDC2 + 6 GCP comparator), Besu 7, Erigon 6, Ethrex 6, Nethermind 6, Reth 6. The <code>job!="node_exporter"</code> filter avoids double-counting, since every EC host also runs node_exporter under <code>role="ec"</code>. The two Grandine custom-image hosts (<code>cc_version="unstable-465c727"</code>) are kept because the EC underneath them is a production image.</p>
<p><strong>Why we use node_exporter, not the EC-internal size metrics.</strong> Each EC-internal metric reports only a slice of the datadir. This is the gap that produced the wrong 26 GB Erigon figure:</p>
<table><thead><tr><th>EC</th><th>EC-internal metric</th><th>Covers</th><th>Root-FS truth</th></tr></thead><tbody><tr><td>Erigon</td><td><code>db_table_size_bytes</code></td><td>MDBX tables (~26 GB)</td><td>~509 GB</td></tr><tr><td>Nethermind</td><td><code>nethermind_db_size</code></td><td>state DB (~778 GB)</td><td>~1,225 GB</td></tr><tr><td>Reth</td><td><code>reth_db_table_size</code></td><td>MDBX tables (~201 GB)</td><td>~1,352 GB (syncing)</td></tr><tr><td>Besu</td><td><code>besu_rocksdb_rocks_db_files_size_bytes</code></td><td>returns 0</td><td>~1,261 GB</td></tr><tr><td>Geth</td><td><code>eth_db_chaindata_disk_size + ..._ancient_size</code></td><td>chaindata + ancient (~1,624 GB)</td><td>~1,688 GB</td></tr><tr><td>Ethrex</td><td><code>datadir_size_bytes</code></td><td>datadir (~499 GB)</td><td>~598 GB</td></tr></tbody></table>
<p>Geth lands within ~60 GB and Ethrex within ~100 GB; the rest understate by hundreds of GB, and Besu by everything. So we use <code>node_filesystem_*</code>, which adds only ~5 to 10 GB of OS and logs on top of the datadir.</p>
<p><strong>Top-bucket caveat.</strong> Ethrex's <code>≥5.00 s</code> (and Reth's 4.00 s on Prysm) sit at the histogram's top bucket, so the true P99 is in the <code>+Inf</code> tail. We do not rank a capped value against a measured one. The read-this-first caveats (no validators, per-CC-observer) apply to every latency figure; where a single P99 is unattributed it is from Nimbus.</p>
<p>The window covers post-Fusaka mainnet conditions only. Pre-Fusaka data (before December 3, 2025) is in cold storage but not included here because <a class="" href="https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes">PeerDAS introduced significant fork-choice timing changes</a> that mix populations.</p>
<p>Dashboard panel definitions for every metric used here are linked from the EC-specific dashboards in our public catalog at <a class="" href="https://docs.stereumlabs.com/docs/dashboards/list/catalog">/docs/dashboards/list/catalog</a>. The per-client dashboards on <a href="https://grafana.stereumlabs.com/" target="_blank" rel="noopener noreferrer" class="">grafana.stereumlabs.com</a> carry the pruning panels above; Ethrex is the exception and ships without a pruning section.</p>
<p>If you maintain an Ethereum execution client and want to clarify what we measured (the Besu RocksDB size series, Reth's intended pruner cadence, the Ethrex Prometheus surface, or Nethermind's inline-newPayload path), write to <a href="mailto:contact@stereumlabs.com" target="_blank" rel="noopener noreferrer" class="">contact@stereumlabs.com</a>. We will append a correction with attribution.</p>]]></content:encoded>
            <category>client comparison</category>
            <category>pruning</category>
            <category>storage</category>
            <category>engine API</category>
            <category>validator duties</category>
            <category>Geth</category>
            <category>Nethermind</category>
            <category>Besu</category>
            <category>Erigon</category>
            <category>Reth</category>
            <category>Ethrex</category>
        </item>
        <item>
            <title><![CDATA[Ethereum reorg accounting: Prysm sees 8×, Lodestar sees 0]]></title>
            <link>https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients</link>
            <guid>https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients</guid>
            <pubDate>Wed, 27 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Six Ethereum consensus clients (Prysm, Lighthouse, Teku, Nimbus, Grandine, Lodestar) report 0 to 6,011 reorgs on identical hardware over 90 days. Here's why.]]></description>
            <content:encoded><![CDATA[<p>A <strong>Prysm</strong> node and a <strong>Lodestar</strong> node on the same chain, on identical hardware, both export <code>beacon_reorgs_total</code>. Over the last 90 days, the Prysm hosts in our Vienna NDC2 fleet incremented that counter <strong>6,011</strong> times. The Lodestar hosts incremented it <strong>zero</strong> times. Both numbers are correct readings of what each implementation chose to count.</p>
<p>This post is a 90-day reorg census across that fleet plus the smaller GCP comparator cohort: every consensus client (CC) paired with every execution client (EC), against the same Ethereum mainnet, with per-host normalization. The questions we answer: which <strong>Prometheus</strong> counter to trust for which question, why the same EC behind two different CCs produces very different reorg numbers, and why a "zero reorgs" reading on some clients is silence rather than safety.</p>
<p><img decoding="async" loading="lazy" alt="90-day Ethereum reorg counts compared across six consensus clients on identical bare-metal hardware" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNjAwIDkwMCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPGRlZnM+CiAgICA8cGF0dGVybiBpZD0iZ3JpZC10aHVtYiIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBwYXR0ZXJuVW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHBhdGggZD0iTSA4MCAwIEwgMCAwIDAgODAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIwLjUiLz4KICAgIDwvcGF0dGVybj4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZC1wcnlzbSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMCUiPgogICAgICA8c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjYjkxYzFjIi8+CiAgICAgIDxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2VhNTgwYyIvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZC10ZWt1IiB4MT0iMCUiIHkxPSIwJSIgeDI9IjEwMCUiIHkyPSIwJSI+CiAgICAgIDxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9IiMxZTQwYWYiLz4KICAgICAgPHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjM2I4MmY2Ii8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLW5pbWJ1cyIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMCUiPgogICAgICA8c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjMTU1ZTc1Ii8+CiAgICAgIDxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzA2YjZkNCIvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZC1ncmFuZGluZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMCUiPgogICAgICA8c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjMGY3NjZlIi8+CiAgICAgIDxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzE0YjhhNiIvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZC1saWdodGhvdXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjEwMCUiIHkyPSIwJSI+CiAgICAgIDxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9IiM2ZDI4ZDkiLz4KICAgICAgPHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjYTc4YmZhIi8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogIDwvZGVmcz4KCiAgPHJlY3Qgd2lkdGg9IjE2MDAiIGhlaWdodD0iOTAwIiBmaWxsPSIjMGUxNTMwIi8+CiAgPHJlY3Qgd2lkdGg9IjE2MDAiIGhlaWdodD0iOTAwIiBmaWxsPSJ1cmwoI2dyaWQtdGh1bWIpIi8+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjE2MDAiIGhlaWdodD0iMTQiIGZpbGw9IiM1MDQ2ZTUiLz4KCiAgPHRleHQgeD0iMTAwIiB5PSIxMDAiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjgiIGZvbnQtd2VpZ2h0PSI2MDAiPlN0ZXJldW1MYWJzPC90ZXh0PgogIDx0ZXh0IHg9IjE1MDAiIHk9IjEwMCIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIyMCIgdGV4dC1hbmNob3I9ImVuZCI+OTAtZGF5IHJlb3JnIGNlbnN1czwvdGV4dD4KCiAgPHRleHQgeD0iODAwIiB5PSIyMDAiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iNTYiIGZvbnQtd2VpZ2h0PSI3MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGxldHRlci1zcGFjaW5nPSItMS41Ij5FdGhlcmV1bSByZW9yZyBhY2NvdW50aW5nIGFjcm9zcyA2IGNsaWVudHM8L3RleHQ+CiAgPHRleHQgeD0iODAwIiB5PSIyNTIiIGZpbGw9IiNjNGI1ZmQiIGZvbnQtc2l6ZT0iMjYiIGZvbnQtd2VpZ2h0PSI0MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPlByeXNtIHNlZXMgOMOXIMK3IExvZGVzdGFyIHNlZXMgMCDCtyBpZGVudGljYWwgaGFyZHdhcmUgwrcgc2FtZSBtYWlubmV0PC90ZXh0PgoKICA8dGV4dCB4PSI4MDAiIHk9IjMyMCIgZmlsbD0iIzk0YTNiOCIgZm9udC1zaXplPSIxOCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+UGVyLUNDIDkwLWRheSByZW9yZyB0b3RhbHMgYWNyb3NzIHRoZSBzYW1lIDYgcHJvZHVjdGlvbiBob3N0cyBlYWNoIMK3IHNhbWUgaGFyZHdhcmUgwrcgc2FtZSBtYWlubmV0PC90ZXh0PgoKICA8ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyODAsIDM4MCkiPgogICAgPHRleHQgeD0iMCIgeT0iMzYiIGZpbGw9IiNmY2E1YTUiIGZvbnQtc2l6ZT0iMjIiIGZvbnQtd2VpZ2h0PSI2MDAiPlByeXNtPC90ZXh0PgogICAgPHJlY3QgeD0iMTcwIiB5PSIxNCIgd2lkdGg9IjgwMCIgaGVpZ2h0PSI0MiIgcng9IjMiIGZpbGw9InVybCgjZ3JhZC1wcnlzbSkiLz4KICAgIDx0ZXh0IHg9Ijk4NSIgeT0iNDQiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMjYiIGZvbnQtd2VpZ2h0PSI3MDAiPjYsMDExPC90ZXh0PgoKICAgIDx0ZXh0IHg9IjAiIHk9IjEwNiIgZmlsbD0iI2JmZGJmZSIgZm9udC1zaXplPSIyMiIgZm9udC13ZWlnaHQ9IjYwMCI+VGVrdTwvdGV4dD4KICAgIDxyZWN0IHg9IjE3MCIgeT0iODQiIHdpZHRoPSI2MDYiIGhlaWdodD0iNDIiIHJ4PSIzIiBmaWxsPSJ1cmwoI2dyYWQtdGVrdSkiLz4KICAgIDx0ZXh0IHg9Ijc5MSIgeT0iMTE0IiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjI2IiBmb250LXdlaWdodD0iNzAwIj40LDU1MTwvdGV4dD4KCiAgICA8dGV4dCB4PSIwIiB5PSIxNzYiIGZpbGw9IiNhNWYzZmMiIGZvbnQtc2l6ZT0iMjIiIGZvbnQtd2VpZ2h0PSI2MDAiPk5pbWJ1czwvdGV4dD4KICAgIDxyZWN0IHg9IjE3MCIgeT0iMTU0IiB3aWR0aD0iNTM2IiBoZWlnaHQ9IjQyIiByeD0iMyIgZmlsbD0idXJsKCNncmFkLW5pbWJ1cykiLz4KICAgIDx0ZXh0IHg9IjcyMSIgeT0iMTg0IiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjI2IiBmb250LXdlaWdodD0iNzAwIj40LDAzMDwvdGV4dD4KCiAgICA8dGV4dCB4PSIwIiB5PSIyNDYiIGZpbGw9IiM5OWY2ZTQiIGZvbnQtc2l6ZT0iMjIiIGZvbnQtd2VpZ2h0PSI2MDAiPkdyYW5kaW5lPC90ZXh0PgogICAgPHJlY3QgeD0iMTcwIiB5PSIyMjQiIHdpZHRoPSI1MzMiIGhlaWdodD0iNDIiIHJ4PSIzIiBmaWxsPSJ1cmwoI2dyYWQtZ3JhbmRpbmUpIi8+CiAgICA8dGV4dCB4PSI3MTgiIHk9IjI1NCIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIyNiIgZm9udC13ZWlnaHQ9IjcwMCI+NCwwMDg8L3RleHQ+CgogICAgPHRleHQgeD0iMCIgeT0iMzE2IiBmaWxsPSIjZGRkNmZlIiBmb250LXNpemU9IjIyIiBmb250LXdlaWdodD0iNjAwIj5MaWdodGhvdXNlPC90ZXh0PgogICAgPHJlY3QgeD0iMTcwIiB5PSIyOTQiIHdpZHRoPSI1MTAiIGhlaWdodD0iNDIiIHJ4PSIzIiBmaWxsPSJ1cmwoI2dyYWQtbGlnaHRob3VzZSkiLz4KICAgIDx0ZXh0IHg9IjY5NSIgeT0iMzI0IiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjI2IiBmb250LXdlaWdodD0iNzAwIj4zLDgyOTwvdGV4dD4KCiAgICA8dGV4dCB4PSIwIiB5PSIzODYiIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMjIiIGZvbnQtd2VpZ2h0PSI2MDAiPkxvZGVzdGFyPC90ZXh0PgogICAgPHJlY3QgeD0iMTcwIiB5PSIzNjQiIHdpZHRoPSI2MCIgaGVpZ2h0PSI0MiIgcng9IjMiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzQ3NTU2OSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtZGFzaGFycmF5PSI2IDUiLz4KICAgIDx0ZXh0IHg9IjIwMCIgeT0iMzk0IiBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjI2IiBmb250LXdlaWdodD0iNzAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj4wPC90ZXh0PgogICAgPHRleHQgeD0iMjQ4IiB5PSIzOTQiIGZpbGw9IiM2NDc0OGIiIGZvbnQtc2l6ZT0iMTgiIGZvbnQtc3R5bGU9Iml0YWxpYyI+Y291bnRlciBuZXZlciBpbmNyZW1lbnRzPC90ZXh0PgogIDwvZz4KCiAgPHJlY3QgeD0iMTAwIiB5PSI4MDAiIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjUwIiByeD0iNCIgZmlsbD0iIzFlMjkzYiIgc3Ryb2tlPSIjMzM0MTU1IiBzdHJva2Utd2lkdGg9IjEiLz4KICA8dGV4dCB4PSI4MDAiIHk9IjgzMiIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIyMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+QWxsIHNpeCBDQ3MgcnVuIG9uIGlkZW50aWNhbCBFUFlDIDk2NTRQIGJhcmUgbWV0YWwgaW4gVmllbm5hIE5EQzI8L3RleHQ+CgogIDx0ZXh0IHg9IjEwMCIgeT0iODg4IiBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE2Ij7CqSBSb2NrTG9naWMgR21iSDwvdGV4dD4KICA8dGV4dCB4PSIxNTAwIiB5PSI4ODgiIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMTYiIHRleHQtYW5jaG9yPSJlbmQiPmRvY3Muc3RlcmV1bWxhYnMuY29tPC90ZXh0Pgo8L3N2Zz4K" width="1600" height="900" class="img_ev3q"></p>
<p><strong>Key findings at a glance:</strong></p>
<ul>
<li class="">Prysm increments <code>beacon_reorgs_total</code> <strong>8× more often than Lighthouse</strong> over 7 days. The gap shrinks to 1.6× over 90 days.</li>
<li class=""><strong>Lodestar's <code>beacon_reorgs_total</code> is 0</strong> for the entire 90-day window. Its decline-reason counter fires roughly 54 times per host per week.</li>
<li class="">The same EC behind two CCs produces <strong>2–5× different counts</strong>: Prysm + Besu reports 69 per host vs Prysm + Nethermind 280.</li>
<li class=""><strong>Geth is the only EC in our fleet</strong> whose Prometheus reorg counter increments at all. Nethermind and Reth export the metric but it never increments; Besu, Erigon, and Ethrex don't export one at all.</li>
<li class="">A single fixed <code>beacon_reorgs_total</code> alert threshold does not port between consensus clients. Re-baseline per CC × EC pair.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-we-measured-the-stereumlabs-ethereum-client-fleet">What we measured: the StereumLabs Ethereum client fleet<a href="https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients#what-we-measured-the-stereumlabs-ethereum-client-fleet" class="hash-link" aria-label="Direct link to What we measured: the StereumLabs Ethereum client fleet" title="Direct link to What we measured: the StereumLabs Ethereum client fleet" translate="no">​</a></h2>
<p>The bare-metal NDC2 fleet in Vienna carries the full pairing matrix: every CC family (Grandine, Lighthouse, Lodestar, Nimbus, Prysm, Teku) crossed with every EC family (Besu, Erigon, Ethrex, Geth, Nethermind, Reth). Each CC family runs on <strong>6 hosts</strong>, one per EC pairing. The GCP comparator cohort runs only Geth on the EC side, paired with one supernode variant of each CC (introduced for PeerDAS custody-group experiments). The full setup is documented in <a class="" href="https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack">the StereumLabs measurement stack post</a>.</p>
<p>All counters in this post come from our <code>prometheus-cold</code> datasource over rolling 7-day, 30-day, and 90-day windows ending around 2026-05-26. Per-host averages divide each family's total reorg count by its host count. Grandine currently carries two extra non-production hosts on a custom image; those are excluded from every comparison below. Queries are reproduced in the methodology section.</p>
<p>The reorg-relevant metric vocabulary, by client, is heterogeneous:</p>
<table><thead><tr><th>Source</th><th>Metric</th><th>Notes</th></tr></thead><tbody><tr><td>Lighthouse, Teku, Nimbus, Grandine, Prysm</td><td><code>beacon_reorgs_total</code></td><td>Shared name, <strong>observed counts diverge by ~8× over 7 days</strong></td></tr><tr><td>Lodestar</td><td><code>beacon_reorgs_total</code></td><td>Counter exists, never increments in our 90-day window</td></tr><tr><td>Lodestar</td><td><code>beacon_fork_choice_reorg_distance_bucket</code></td><td>Histogram populated even while <code>beacon_reorgs_total</code> stays at zero</td></tr><tr><td>Prysm</td><td><code>reorg_depth_bucket</code>, <code>reorg_distance_bucket</code></td><td>Two Prysm-specific histograms with deeper bins</td></tr><tr><td>Prysm</td><td><code>beacon_late_block_attempted_reorgs</code></td><td>Proposer-boost reorg attempts, separate counter</td></tr><tr><td>Nimbus</td><td><code>beacon_safe_reorgs_total</code></td><td>Reorgs after the proposer-boost timing window</td></tr><tr><td>Lodestar</td><td><code>beacon_fork_choice_not_reorged_reason_total{reason}</code></td><td>Why a candidate reorg was declined</td></tr><tr><td>Geth</td><td><code>chain_reorg_executes</code>, <code>chain_reorg_add</code>, <code>chain_reorg_drop</code></td><td>EC-side canonical chain rewrites</td></tr><tr><td>Nethermind</td><td><code>nethermind_reorganizations</code>, <code>nethermind_transactions_reorged</code></td><td>Series exists, never increments in window</td></tr><tr><td>Reth</td><td><code>reth_blockchain_tree_reorgs</code>, <code>reth_blockchain_tree_latest_reorg_depth</code></td><td>Series exists, never increments in window</td></tr><tr><td>Besu, Erigon, Ethrex</td><td><em>no reorg counter exported on Prometheus</em></td><td>DEBUG logs not audited in this round</td></tr></tbody></table>
<p>That table alone tells most of the story. Before we look at a number, we already know that "is my client reorging more than it used to" is a question with six different correct answers.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-each-ethereum-consensus-client-reports-as-a-reorg">What each Ethereum consensus client reports as a reorg<a href="https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients#what-each-ethereum-consensus-client-reports-as-a-reorg" class="hash-link" aria-label="Direct link to What each Ethereum consensus client reports as a reorg" title="Direct link to What each Ethereum consensus client reports as a reorg" translate="no">​</a></h2>
<p>Across all six CCs, 6 production hosts each, here is what <code>beacon_reorgs_total</code> accumulated over our 7-, 30-, and 90-day windows:</p>
<ul>
<li class=""><strong>Prysm</strong>: 1,373 reorgs in 7d (229 per host), 502 per host over 30d, 1,002 per host over 90d</li>
<li class=""><strong>Teku</strong>: 282 in 7d (47 per host), 209 per host over 30d, 759 per host over 90d</li>
<li class=""><strong>Nimbus</strong>: 210 in 7d (35 per host), 172 per host over 30d, 672 per host over 90d</li>
<li class=""><strong>Lighthouse</strong>: 171 in 7d (29 per host), 159 per host over 30d, 638 per host over 90d</li>
<li class=""><strong>Grandine</strong>: 153 in 7d (26 per host), 163 per host over 30d, 668 per host over 90d</li>
<li class=""><strong>Lodestar</strong>: 0 in 7d, 0 over 30d, 0 over 90d</li>
</ul>
<p>A few observations:</p>
<ul>
<li class=""><strong>Prysm increments roughly 8× more often than Lighthouse over 7 days.</strong> Over 30 days the multiple drops to 3.2×, over 90 days to 1.6×. Either Prysm had a spike in recent days (it did, see below), or Prysm's counter responds to short-lived events that other clients smooth out across longer windows. Both apply here.</li>
<li class=""><strong>Grandine, Lighthouse, Nimbus, and Teku land within a 1.8× band over 7 days</strong> (Grandine 26, Teku 47 per host) and tighten to a 1.2× band over 90 days. That is the tightest cluster in the dataset.</li>
<li class=""><strong>Lodestar increments the counter zero times.</strong> Not "low": exactly zero, across 90 days and 6 hosts. The Lodestar section below describes what it does instead.</li>
</ul>
<p>The 7-day-to-90-day collapse on Prysm is the first practical lesson: <strong>short reorg windows can mislead</strong>. In this single 7-day window Prysm registered two sustained spikes that no other CC registered and that no EC-side counter registered either. An alert calibrated to a Lighthouse-shaped baseline would have fired twice on Prysm during this week alone, both times without a chain event behind it.</p>
<p>Cross-CC divergence at this scale is not unique to reorgs. The same six consensus clients showed a <a class="" href="https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients">50× spread in blob gossip verification latency on identical hardware</a>. Different metric, different mechanism, same conclusion: a shared metric name does not guarantee a shared definition.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-each-execution-client-reports-geth-nethermind-reth-and-the-rest">What each execution client reports: Geth, Nethermind, Reth, and the rest<a href="https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients#what-each-execution-client-reports-geth-nethermind-reth-and-the-rest" class="hash-link" aria-label="Direct link to What each execution client reports: Geth, Nethermind, Reth, and the rest" title="Direct link to What each execution client reports: Geth, Nethermind, Reth, and the rest" translate="no">​</a></h2>
<p>The EC side is simpler, and emptier. Host counts vary by EC: Geth runs on 13 hosts (7 NDC2 + 6 GCP comparator), Besu on 7, all others on 6.</p>
<ul>
<li class=""><strong>Geth</strong>: <code>chain_reorg_executes</code> increments. 7d: 414 reorgs (32 per host); 90d: 7,383 (568 per host).</li>
<li class=""><strong>Nethermind</strong>: <code>nethermind_reorganizations</code> is exposed, scraped, and stays at 0 across the 90-day window.</li>
<li class=""><strong>Reth</strong>: <code>reth_blockchain_tree_reorgs</code> is exposed, scraped, and stays at 0 across the 90-day window.</li>
<li class=""><strong>Besu, Erigon, Ethrex</strong>: no Prometheus reorg counter exported at all.</li>
</ul>
<p>Geth is the only EC in our fleet whose counter increments. Nethermind and Reth carry the metric in their vocabulary, both series are registered and scraped successfully, but neither has incremented in 90 days on any host. We did not review either client's source to determine whether the increment path is unreachable on mainnet, intentionally gated, or implements a stricter definition of "reorg" than Geth does. That distinction is for the client teams to clarify. (Neither Nethermind nor Reth is deployed in our GCP cohort, so the 90-day window covers only the NDC2 hosts for those two clients.)</p>
<p>Besu, Erigon, and Ethrex do not export a Prometheus reorg counter at all. We have not in this round audited the DEBUG-level logs of those three clients for reorg events; it is possible that the events are visible there even though no counter is exposed. What we can say is that no Prometheus alert rule lives over them for this question today.</p>
<p>EC-side observability gaps are an existing pattern on this fleet. The <a class="" href="https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026">EC sync-speed comparison</a> found that initial sync time ranged from 1.5 hours to over 8 days on identical hardware across the same six clients, partly because each one logs and exports its sync progress differently. Reorg counters are the steady-state analogue of that observation.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-cc--ec-pairing-matrix-where-reorg-counts-diverge-most">The CC × EC pairing matrix: where reorg counts diverge most<a href="https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients#the-cc--ec-pairing-matrix-where-reorg-counts-diverge-most" class="hash-link" aria-label="Direct link to The CC × EC pairing matrix: where reorg counts diverge most" title="Direct link to The CC × EC pairing matrix: where reorg counts diverge most" translate="no">​</a></h2>
<p>The strongest finding in this dataset is not at the CC level or the EC level. It is in the <strong>CC × EC pairings</strong>.</p>
<p><img decoding="async" loading="lazy" alt="Heatmap of Ethereum reorg counts per host across all consensus client × execution client pairings, 7-day window" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxODAwIDExODAiIGZvbnQtZmFtaWx5PSItYXBwbGUtc3lzdGVtLCAnU2Vnb2UgVUknLCBSb2JvdG8sIEhlbHZldGljYSwgQXJpYWwsIHNhbnMtc2VyaWYiPgogIDxkZWZzPgogICAgPHBhdHRlcm4gaWQ9ImdyaWQtaGVhdCIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBwYXR0ZXJuVW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHBhdGggZD0iTSA4MCAwIEwgMCAwIDAgODAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIwLjUiLz4KICAgIDwvcGF0dGVybj4KICAgIDxwYXR0ZXJuIGlkPSJkaWFnLXN0cmlwZSIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgd2lkdGg9IjEyIiBoZWlnaHQ9IjEyIiBwYXR0ZXJuVHJhbnNmb3JtPSJyb3RhdGUoNDUpIj4KICAgICAgPHJlY3Qgd2lkdGg9IjEyIiBoZWlnaHQ9IjEyIiBmaWxsPSIjMWUyOTNiIi8+CiAgICAgIDxsaW5lIHgxPSIwIiB5MT0iMCIgeDI9IjAiIHkyPSIxMiIgc3Ryb2tlPSIjNDc1NTY5IiBzdHJva2Utd2lkdGg9IjMiLz4KICAgIDwvcGF0dGVybj4KICAgIDxtYXJrZXIgaWQ9ImFyci1hbm5vdCIgdmlld0JveD0iMCAwIDEwIDEwIiByZWZYPSI5IiByZWZZPSI1IiBtYXJrZXJXaWR0aD0iNyIgbWFya2VySGVpZ2h0PSI3IiBvcmllbnQ9ImF1dG8iPgogICAgICA8cGF0aCBkPSJNIDAgMCBMIDEwIDUgTCAwIDEwIHoiIGZpbGw9IiNmZGU2OGEiLz4KICAgIDwvbWFya2VyPgogIDwvZGVmcz4KCiAgPHJlY3Qgd2lkdGg9IjE4MDAiIGhlaWdodD0iMTE4MCIgZmlsbD0iIzBlMTUzMCIvPgogIDxyZWN0IHdpZHRoPSIxODAwIiBoZWlnaHQ9IjExODAiIGZpbGw9InVybCgjZ3JpZC1oZWF0KSIvPgoKICA8dGV4dCB4PSI5MDAiIHk9IjcwIiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjM0IiBmb250LXdlaWdodD0iNzAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5QZXItaG9zdCA3LWRheSByZW9yZyBjb3VudHMgYnkgcGFpcmluZzwvdGV4dD4KICA8dGV4dCB4PSI5MDAiIHk9IjExMCIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxOCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+U2FtZSBtZXRyaWMgbmFtZSAoPHRzcGFuIGZvbnQtZmFtaWx5PSJNZW5sbywgbW9ub3NwYWNlIiBmaWxsPSIjZmRlNjhhIj5iZWFjb25fcmVvcmdzX3RvdGFsPC90c3Bhbj4pIMK3IHNhbWUgY2hhaW4gwrcgc2FtZSBoYXJkd2FyZSDCtyA2IHByb2R1Y3Rpb24gaG9zdHMgcGVyIENDIGZhbWlseTwvdGV4dD4KCiAgPHRleHQgeD0iMjIwIiB5PSIxNzAiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTYiIGZvbnQtd2VpZ2h0PSI3MDAiIGxldHRlci1zcGFjaW5nPSIyIj5FWEVDVVRJT04gQ0xJRU5UPC90ZXh0PgogIDx0ZXh0IHg9IjE5MCIgeT0iNjAwIiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE2IiBmb250LXdlaWdodD0iNzAwIiBsZXR0ZXItc3BhY2luZz0iMiIgdHJhbnNmb3JtPSJyb3RhdGUoLTkwIDE5MCA2MDApIj5DT05TRU5TVVMgQ0xJRU5UPC90ZXh0PgoKICA8ZyBmb250LXNpemU9IjIyIiBmb250LXdlaWdodD0iNjAwIiBmaWxsPSIjZmZmZmZmIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj4KICAgIDx0ZXh0IHg9IjUwMCIgeT0iMjE1Ij5CZXN1PC90ZXh0PgogICAgPHRleHQgeD0iNzAwIiB5PSIyMTUiPkVyaWdvbjwvdGV4dD4KICAgIDx0ZXh0IHg9IjkwMCIgeT0iMjE1Ij5FdGhyZXg8L3RleHQ+CiAgICA8dGV4dCB4PSIxMTAwIiB5PSIyMTUiPkdldGg8L3RleHQ+CiAgICA8dGV4dCB4PSIxMzAwIiB5PSIyMTUiPk5ldGhlcm1pbmQ8L3RleHQ+CiAgICA8dGV4dCB4PSIxNTAwIiB5PSIyMTUiPlJldGg8L3RleHQ+CiAgPC9nPgoKICA8ZyBmb250LXNpemU9IjIyIiBmb250LXdlaWdodD0iNjAwIiBmaWxsPSIjZmZmZmZmIiB0ZXh0LWFuY2hvcj0iZW5kIj4KICAgIDx0ZXh0IHg9IjM4MCIgeT0iMzA3Ij5HcmFuZGluZTwvdGV4dD4KICAgIDx0ZXh0IHg9IjM4MCIgeT0iNDI3Ij5MaWdodGhvdXNlPC90ZXh0PgogICAgPHRleHQgeD0iMzgwIiB5PSI1NDciPkxvZGVzdGFyPC90ZXh0PgogICAgPHRleHQgeD0iMzgwIiB5PSI2NjciPk5pbWJ1czwvdGV4dD4KICAgIDx0ZXh0IHg9IjM4MCIgeT0iNzg3Ij5QcnlzbTwvdGV4dD4KICAgIDx0ZXh0IHg9IjM4MCIgeT0iOTA3Ij5UZWt1PC90ZXh0PgogIDwvZz4KCiAgPGcgc3Ryb2tlPSIjMGUxNTMwIiBzdHJva2Utd2lkdGg9IjIiPgogICAgPHJlY3QgeD0iNDAwIiB5PSIyNDAiIHdpZHRoPSIyMDAiIGhlaWdodD0iMTIwIiBmaWxsPSIjMDY1ZjQ2Ii8+CiAgICA8cmVjdCB4PSI2MDAiIHk9IjI0MCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIxMjAiIGZpbGw9IiMwNjVmNDYiLz4KICAgIDxyZWN0IHg9IjgwMCIgeT0iMjQwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjEyMCIgZmlsbD0iIzA2NGUzYiIvPgogICAgPHJlY3QgeD0iMTAwMCIgeT0iMjQwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjEyMCIgZmlsbD0iIzE1ODAzZCIvPgogICAgPHJlY3QgeD0iMTIwMCIgeT0iMjQwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjEyMCIgZmlsbD0iIzA2NWY0NiIvPgogICAgPHJlY3QgeD0iMTQwMCIgeT0iMjQwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjEyMCIgZmlsbD0iIzA2NWY0NiIvPgoKICAgIDxyZWN0IHg9IjQwMCIgeT0iMzYwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjEyMCIgZmlsbD0iIzA2NWY0NiIvPgogICAgPHJlY3QgeD0iNjAwIiB5PSIzNjAiIHdpZHRoPSIyMDAiIGhlaWdodD0iMTIwIiBmaWxsPSJ1cmwoI2RpYWctc3RyaXBlKSIvPgogICAgPHJlY3QgeD0iODAwIiB5PSIzNjAiIHdpZHRoPSIyMDAiIGhlaWdodD0iMTIwIiBmaWxsPSIjMDY1ZjQ2Ii8+CiAgICA8cmVjdCB4PSIxMDAwIiB5PSIzNjAiIHdpZHRoPSIyMDAiIGhlaWdodD0iMTIwIiBmaWxsPSIjMTU4MDNkIi8+CiAgICA8cmVjdCB4PSIxMjAwIiB5PSIzNjAiIHdpZHRoPSIyMDAiIGhlaWdodD0iMTIwIiBmaWxsPSIjMTU4MDNkIi8+CiAgICA8cmVjdCB4PSIxNDAwIiB5PSIzNjAiIHdpZHRoPSIyMDAiIGhlaWdodD0iMTIwIiBmaWxsPSIjMTU4MDNkIi8+CgogICAgPHJlY3QgeD0iNDAwIiB5PSI0ODAiIHdpZHRoPSIyMDAiIGhlaWdodD0iMTIwIiBmaWxsPSIjMzM0MTU1Ii8+CiAgICA8cmVjdCB4PSI2MDAiIHk9IjQ4MCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIxMjAiIGZpbGw9IiMzMzQxNTUiLz4KICAgIDxyZWN0IHg9IjgwMCIgeT0iNDgwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjEyMCIgZmlsbD0iIzMzNDE1NSIvPgogICAgPHJlY3QgeD0iMTAwMCIgeT0iNDgwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjEyMCIgZmlsbD0iIzMzNDE1NSIvPgogICAgPHJlY3QgeD0iMTIwMCIgeT0iNDgwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjEyMCIgZmlsbD0iIzMzNDE1NSIvPgogICAgPHJlY3QgeD0iMTQwMCIgeT0iNDgwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjEyMCIgZmlsbD0iIzMzNDE1NSIvPgoKICAgIDxyZWN0IHg9IjQwMCIgeT0iNjAwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjEyMCIgZmlsbD0iIzA2NWY0NiIvPgogICAgPHJlY3QgeD0iNjAwIiB5PSI2MDAiIHdpZHRoPSIyMDAiIGhlaWdodD0iMTIwIiBmaWxsPSIjMTU4MDNkIi8+CiAgICA8cmVjdCB4PSI4MDAiIHk9IjYwMCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIxMjAiIGZpbGw9IiMwNjVmNDYiLz4KICAgIDxyZWN0IHg9IjEwMDAiIHk9IjYwMCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIxMjAiIGZpbGw9IiMxNTgwM2QiLz4KICAgIDxyZWN0IHg9IjEyMDAiIHk9IjYwMCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIxMjAiIGZpbGw9IiMxNTgwM2QiLz4KICAgIDxyZWN0IHg9IjE0MDAiIHk9IjYwMCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIxMjAiIGZpbGw9IiMxNTgwM2QiLz4KCiAgICA8cmVjdCB4PSI0MDAiIHk9IjcyMCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIxMjAiIGZpbGw9IiNjYThhMDQiLz4KICAgIDxyZWN0IHg9IjYwMCIgeT0iNzIwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjEyMCIgZmlsbD0iI2I5MWMxYyIvPgogICAgPHJlY3QgeD0iODAwIiB5PSI3MjAiIHdpZHRoPSIyMDAiIGhlaWdodD0iMTIwIiBmaWxsPSIjYzI0MTBjIi8+CiAgICA8cmVjdCB4PSIxMDAwIiB5PSI3MjAiIHdpZHRoPSIyMDAiIGhlaWdodD0iMTIwIiBmaWxsPSIjYjkxYzFjIi8+CiAgICA8cmVjdCB4PSIxMjAwIiB5PSI3MjAiIHdpZHRoPSIyMDAiIGhlaWdodD0iMTIwIiBmaWxsPSIjOTkxYjFiIi8+CiAgICA8cmVjdCB4PSIxNDAwIiB5PSI3MjAiIHdpZHRoPSIyMDAiIGhlaWdodD0iMTIwIiBmaWxsPSIjYjkxYzFjIi8+CgogICAgPHJlY3QgeD0iNDAwIiB5PSI4NDAiIHdpZHRoPSIyMDAiIGhlaWdodD0iMTIwIiBmaWxsPSIjMDY1ZjQ2Ii8+CiAgICA8cmVjdCB4PSI2MDAiIHk9Ijg0MCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIxMjAiIGZpbGw9IiMxNTgwM2QiLz4KICAgIDxyZWN0IHg9IjgwMCIgeT0iODQwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjEyMCIgZmlsbD0iIzA2NWY0NiIvPgogICAgPHJlY3QgeD0iMTAwMCIgeT0iODQwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjEyMCIgZmlsbD0iIzE1ODAzZCIvPgogICAgPHJlY3QgeD0iMTIwMCIgeT0iODQwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjEyMCIgZmlsbD0iIzE1ODAzZCIvPgogICAgPHJlY3QgeD0iMTQwMCIgeT0iODQwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjEyMCIgZmlsbD0iI2MyNDEwYyIvPgogIDwvZz4KCiAgPGcgZm9udC1zaXplPSIzMiIgZm9udC13ZWlnaHQ9IjcwMCIgZmlsbD0iI2ZmZmZmZiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+CiAgICA8dGV4dCB4PSI1MDAiIHk9IjMxMCI+MTcuNTwvdGV4dD4KICAgIDx0ZXh0IHg9IjcwMCIgeT0iMzEwIj4yMDwvdGV4dD4KICAgIDx0ZXh0IHg9IjkwMCIgeT0iMzEwIj4xMS41PC90ZXh0PgogICAgPHRleHQgeD0iMTEwMCIgeT0iMzEwIj4zNTwvdGV4dD4KICAgIDx0ZXh0IHg9IjEzMDAiIHk9IjMxMCI+MjA8L3RleHQ+CiAgICA8dGV4dCB4PSIxNTAwIiB5PSIzMTAiPjIwPC90ZXh0PgoKICAgIDx0ZXh0IHg9IjUwMCIgeT0iNDMwIj4xNzwvdGV4dD4KICAgIDx0ZXh0IHg9IjcwMCIgeT0iNDMwIiBmb250LXNpemU9IjIwIiBmaWxsPSIjOTRhM2I4IiBmb250LXN0eWxlPSJpdGFsaWMiPm5vIGRhdGE8L3RleHQ+CiAgICA8dGV4dCB4PSI5MDAiIHk9IjQzMCI+MTYuNTwvdGV4dD4KICAgIDx0ZXh0IHg9IjExMDAiIHk9IjQzMCI+MzU8L3RleHQ+CiAgICA8dGV4dCB4PSIxMzAwIiB5PSI0MzAiPjM1PC90ZXh0PgogICAgPHRleHQgeD0iMTUwMCIgeT0iNDMwIj4zNDwvdGV4dD4KCiAgICA8dGV4dCB4PSI1MDAiIHk9IjU1MCIgZmlsbD0iIzk0YTNiOCI+MDwvdGV4dD4KICAgIDx0ZXh0IHg9IjcwMCIgeT0iNTUwIiBmaWxsPSIjOTRhM2I4Ij4wPC90ZXh0PgogICAgPHRleHQgeD0iOTAwIiB5PSI1NTAiIGZpbGw9IiM5NGEzYjgiPjA8L3RleHQ+CiAgICA8dGV4dCB4PSIxMTAwIiB5PSI1NTAiIGZpbGw9IiM5NGEzYjgiPjA8L3RleHQ+CiAgICA8dGV4dCB4PSIxMzAwIiB5PSI1NTAiIGZpbGw9IiM5NGEzYjgiPjA8L3RleHQ+CiAgICA8dGV4dCB4PSIxNTAwIiB5PSI1NTAiIGZpbGw9IiM5NGEzYjgiPjA8L3RleHQ+CgogICAgPHRleHQgeD0iNTAwIiB5PSI2NzAiPjE3LjU8L3RleHQ+CiAgICA8dGV4dCB4PSI3MDAiIHk9IjY3MCI+MzU8L3RleHQ+CiAgICA8dGV4dCB4PSI5MDAiIHk9IjY3MCI+MTc8L3RleHQ+CiAgICA8dGV4dCB4PSIxMTAwIiB5PSI2NzAiPjM1PC90ZXh0PgogICAgPHRleHQgeD0iMTMwMCIgeT0iNjcwIj4zNTwvdGV4dD4KICAgIDx0ZXh0IHg9IjE1MDAiIHk9IjY3MCI+MzY8L3RleHQ+CgogICAgPHRleHQgeD0iNTAwIiB5PSI3OTAiPjY5PC90ZXh0PgogICAgPHRleHQgeD0iNzAwIiB5PSI3OTAiPjIzNzwvdGV4dD4KICAgIDx0ZXh0IHg9IjkwMCIgeT0iNzkwIj4xMTQ8L3RleHQ+CiAgICA8dGV4dCB4PSIxMTAwIiB5PSI3OTAiPjI0MDwvdGV4dD4KICAgIDx0ZXh0IHg9IjEzMDAiIHk9Ijc5MCI+MjgwPC90ZXh0PgogICAgPHRleHQgeD0iMTUwMCIgeT0iNzkwIj4yNDk8L3RleHQ+CgogICAgPHRleHQgeD0iNTAwIiB5PSI5MTAiPjE4PC90ZXh0PgogICAgPHRleHQgeD0iNzAwIiB5PSI5MTAiPjM4PC90ZXh0PgogICAgPHRleHQgeD0iOTAwIiB5PSI5MTAiPjE4PC90ZXh0PgogICAgPHRleHQgeD0iMTEwMCIgeT0iOTEwIj4zNTwvdGV4dD4KICAgIDx0ZXh0IHg9IjEzMDAiIHk9IjkxMCI+Mzc8L3RleHQ+CiAgICA8dGV4dCB4PSIxNTAwIiB5PSI5MTAiPjEwMDwvdGV4dD4KICA8L2c+CgogIDxnPgogICAgPHBhdGggZD0iTSAzMDAgNjYwIEwgMzgwIDc2MCIgc3Ryb2tlPSIjZmRlNjhhIiBzdHJva2Utd2lkdGg9IjIiIGZpbGw9Im5vbmUiIG1hcmtlci1lbmQ9InVybCgjYXJyLWFubm90KSIvPgogICAgPHJlY3QgeD0iODAiIHk9IjYxMCIgd2lkdGg9IjIyMCIgaGVpZ2h0PSI2MCIgcng9IjQiIGZpbGw9IiMxZTI5M2IiIHN0cm9rZT0iI2ZkZTY4YSIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICAgIDx0ZXh0IHg9IjE5MCIgeT0iNjM1IiBmaWxsPSIjZmRlNjhhIiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iNzAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5QcnlzbSArIEJlc3U8L3RleHQ+CiAgICA8dGV4dCB4PSIxOTAiIHk9IjY1NyIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9Im1pZGRsZSI+MS424oCTNMOXIGxvd2VyIHRoYW4gb3RoZXIgUHJ5c20gcm93czwvdGV4dD4KCiAgICA8cGF0aCBkPSJNIDE1MzAgNzAwIEwgMTM4MCA3NTAiIHN0cm9rZT0iI2ZkZTY4YSIgc3Ryb2tlLXdpZHRoPSIyIiBmaWxsPSJub25lIiBtYXJrZXItZW5kPSJ1cmwoI2Fyci1hbm5vdCkiLz4KICAgIDxyZWN0IHg9IjE1NDAiIHk9IjY0MCIgd2lkdGg9IjIyMCIgaGVpZ2h0PSI2MCIgcng9IjQiIGZpbGw9IiMxZTI5M2IiIHN0cm9rZT0iI2ZkZTY4YSIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICAgIDx0ZXh0IHg9IjE2NTAiIHk9IjY2NSIgZmlsbD0iI2ZkZTY4YSIgZm9udC1zaXplPSIxNCIgZm9udC13ZWlnaHQ9IjcwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+UHJ5c20gKyBOZXRoZXJtaW5kPC90ZXh0PgogICAgPHRleHQgeD0iMTY1MCIgeT0iNjg3IiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5oaWdoZXN0IGNlbGwgb24gdGhlIG1hdHJpeDwvdGV4dD4KCiAgICA8cGF0aCBkPSJNIDE2NDAgMTAwMCBMIDE1MzAgOTQwIiBzdHJva2U9IiNmZGU2OGEiIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0ibm9uZSIgbWFya2VyLWVuZD0idXJsKCNhcnItYW5ub3QpIi8+CiAgICA8cmVjdCB4PSIxNTQwIiB5PSIxMDAwIiB3aWR0aD0iMjIwIiBoZWlnaHQ9IjYwIiByeD0iNCIgZmlsbD0iIzFlMjkzYiIgc3Ryb2tlPSIjZmRlNjhhIiBzdHJva2Utd2lkdGg9IjEuNSIvPgogICAgPHRleHQgeD0iMTY1MCIgeT0iMTAyNSIgZmlsbD0iI2ZkZTY4YSIgZm9udC1zaXplPSIxNCIgZm9udC13ZWlnaHQ9IjcwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+VGVrdSArIFJldGg8L3RleHQ+CiAgICA8dGV4dCB4PSIxNjUwIiB5PSIxMDQ3IiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj4yLjbigJM1LjXDlyBoaWdoZXIgdGhhbiBvdGhlciBUZWt1IHJvd3M8L3RleHQ+CiAgPC9nPgoKICA8ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0MDAsIDEwMTApIj4KICAgIDx0ZXh0IHg9IjAiIHk9IjAiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTQiIGZvbnQtd2VpZ2h0PSI3MDAiIGxldHRlci1zcGFjaW5nPSIxIj5MRUdFTkQgwrcgcGVyLWhvc3QgNy1kYXkgcmVvcmcgY291bnQ8L3RleHQ+CiAgICA8ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLCAxNikiPgogICAgICA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iNDAiIGhlaWdodD0iMjIiIGZpbGw9IiMzMzQxNTUiLz4KICAgICAgPHRleHQgeD0iNTAiIHk9IjE3IiBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE0Ij4wIChjb3VudGVyIG5ldmVyIGluY3JlbWVudHMpPC90ZXh0PgogICAgICA8cmVjdCB4PSIyODAiIHk9IjAiIHdpZHRoPSI0MCIgaGVpZ2h0PSIyMiIgZmlsbD0iIzA2NWY0NiIvPgogICAgICA8dGV4dCB4PSIzMzAiIHk9IjE3IiBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE0Ij4x4oCTMjU8L3RleHQ+CiAgICAgIDxyZWN0IHg9IjQwMCIgeT0iMCIgd2lkdGg9IjQwIiBoZWlnaHQ9IjIyIiBmaWxsPSIjMTU4MDNkIi8+CiAgICAgIDx0ZXh0IHg9IjQ1MCIgeT0iMTciIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMTQiPjI14oCTNDA8L3RleHQ+CiAgICAgIDxyZWN0IHg9IjUyMCIgeT0iMCIgd2lkdGg9IjQwIiBoZWlnaHQ9IjIyIiBmaWxsPSIjY2E4YTA0Ii8+CiAgICAgIDx0ZXh0IHg9IjU3MCIgeT0iMTciIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMTQiPjQw4oCTMTAwPC90ZXh0PgogICAgICA8cmVjdCB4PSI2NTAiIHk9IjAiIHdpZHRoPSI0MCIgaGVpZ2h0PSIyMiIgZmlsbD0iI2MyNDEwYyIvPgogICAgICA8dGV4dCB4PSI3MDAiIHk9IjE3IiBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE0Ij4xMDDigJMyMDA8L3RleHQ+CiAgICAgIDxyZWN0IHg9Ijc4MCIgeT0iMCIgd2lkdGg9IjQwIiBoZWlnaHQ9IjIyIiBmaWxsPSIjYjkxYzFjIi8+CiAgICAgIDx0ZXh0IHg9IjgzMCIgeT0iMTciIGZpbGw9IiM5NGEzYjgiIGZvbnQtc2l6ZT0iMTQiPjIwMCs8L3RleHQ+CiAgICAgIDxyZWN0IHg9IjkwMCIgeT0iMCIgd2lkdGg9IjQwIiBoZWlnaHQ9IjIyIiBmaWxsPSJ1cmwoI2RpYWctc3RyaXBlKSIvPgogICAgICA8dGV4dCB4PSI5NTAiIHk9IjE3IiBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE0Ij5ubyBkYXRhIChjb3VudGVyIG5vdCByZWdpc3RlcmVkKTwvdGV4dD4KICAgIDwvZz4KICA8L2c+CgogIDx0ZXh0IHg9IjEwMCIgeT0iMTE1MCIgZmlsbD0iIzk0YTNiOCIgZm9udC1zaXplPSIxNiI+wqkgUm9ja0xvZ2ljIEdtYkggwrcgU3RlcmV1bUxhYnM8L3RleHQ+CiAgPHRleHQgeD0iMTcwMCIgeT0iMTE1MCIgZmlsbD0iIzk0YTNiOCIgZm9udC1zaXplPSIxNiIgdGV4dC1hbmNob3I9ImVuZCI+ZGF0YTogcHJvbWV0aGV1cy1jb2xkIMK3IDdkIHdpbmRvdyBlbmRpbmcgMjAyNi0wNS0yNjwvdGV4dD4KPC9zdmc+Cg==" width="1800" height="1180" class="img_ev3q"></p>
<p>The Lighthouse + Erigon cell is a data gap: two hosts are up in that pairing, but <code>beacon_reorgs_total</code> returned no series for them in the queried window. Either the counter has not registered on those hosts yet (a recent deployment), or there is a pairing-specific instrumentation gap. We flag the gap rather than impute a number.</p>
<p>Three patterns emerge from the matrix:</p>
<ol>
<li class=""><strong>Most CCs split their pairings into two tiers.</strong> For Lighthouse, Nimbus, Teku and Grandine, the same metric counts roughly twice as often when paired with Geth, Nethermind or Reth than when paired with Besu or Ethrex. Nimbus, for example, sits at 17–18 per host with Besu and Ethrex and at 35–36 with the other four ECs. The split looks like an EC-side property propagating into the CC counter, not a CC property.</li>
<li class=""><strong>Prysm + Besu and Teku + Reth are real outliers.</strong> Prysm + Besu is 69 per host, while every other Prysm pairing lands between 114 (Ethrex) and 280 (Nethermind), a 1.6–4× spread that is not visible in any other CC row. Teku + Reth sits at 100 per host, while every other Teku pairing lands between 18 and 38, a 2.6–5.5× elevation.</li>
<li class=""><strong>Prysm operates on a different scale.</strong> Even the lowest Prysm pairing (Besu, 69) is higher than the highest pairing of any other CC except Teku + Reth.</li>
</ol>
<p>The same metric (<code>beacon_reorgs_total</code>) responds to the paired EC's behaviour, not just to the chain. Block import timing, attestation late-arrival rates, and engine-API forkchoice update latency on the EC side feed back into the CC's fork-choice loop, and the counters reflect that. We previously characterised the same EC↔CC coupling from a different angle in the <a class="" href="https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos">Erigon + Caplin standalone vs classic comparison</a>, where collapsing both layers into one binary moved EVM execution by ~25% and MDBX commits by ~2× on the same engine-API timing surface, observed from the inside. We are not yet in a position to attribute the Prysm + Besu reduction or the Teku + Reth elevation to a specific mechanism; the pairings are flagged here as findings for follow-up.</p>
<p>Practical takeaway for operators: <strong>if you swap your EC, expect your CC reorg numbers to move</strong>. If you alert on a fixed <code>rate(beacon_reorgs_total[15m])</code> threshold, that threshold needs to be re-baselined after any EC change. Otherwise you are paging yourself for a re-baselined client behavior rather than a chain event.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-prysm-reorg-rate-spike-a-counter-responding-to-what">The Prysm reorg-rate spike: a counter responding to what?<a href="https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients#the-prysm-reorg-rate-spike-a-counter-responding-to-what" class="hash-link" aria-label="Direct link to The Prysm reorg-rate spike: a counter responding to what?" title="Direct link to The Prysm reorg-rate spike: a counter responding to what?" translate="no">​</a></h2>
<p>Across 7 days, Prysm increments <code>beacon_reorgs_total</code> 1,373 times. Across 90 days, 6,011. That means <strong>23% of Prysm's 90-day total accumulated in the last 7 days</strong>. The other CCs do not show the same concentration: Lighthouse's 7-day-to-90-day ratio is 4%, Teku's is 6%, Grandine's is 4%, Nimbus's is 5%.</p>
<p>The hourly time series confirms two distinct sustained spikes within the 7-day window. One lasted roughly 15 hours, the second roughly 36 hours. During both, Prysm's fleet-wide rate jumped from a baseline near 0.0014 reorgs/sec (across all 6 Prysm hosts) to a sustained 0.005–0.010 reorgs/sec, a 4× to 7× elevation. <strong>No other CC counter and no EC counter registered the spikes.</strong> Geth's <code>chain_reorg_executes</code> stayed at its normal pulse pattern (around 0.0034 reorgs/sec across its 13 hosts) throughout both windows.</p>
<p><img decoding="async" loading="lazy" alt="Prysm Ethereum reorg-rate spikes compared to Lighthouse and Geth chain_reorg_executes over 7 days" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxODAwIDk1MCIgZm9udC1mYW1pbHk9Ii1hcHBsZS1zeXN0ZW0sICdTZWdvZSBVSScsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiI+CiAgPGRlZnM+CiAgICA8cGF0dGVybiBpZD0iZ3JpZC1zcGlrZSIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBwYXR0ZXJuVW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHBhdGggZD0iTSA4MCAwIEwgMCAwIDAgODAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIwLjUiLz4KICAgIDwvcGF0dGVybj4KICA8L2RlZnM+CgogIDxyZWN0IHdpZHRoPSIxODAwIiBoZWlnaHQ9Ijk1MCIgZmlsbD0iIzBlMTUzMCIvPgogIDxyZWN0IHdpZHRoPSIxODAwIiBoZWlnaHQ9Ijk1MCIgZmlsbD0idXJsKCNncmlkLXNwaWtlKSIvPgoKICA8dGV4dCB4PSI5MDAiIHk9IjcwIiBmaWxsPSIjZmZmZmZmIiBmb250LXNpemU9IjMyIiBmb250LXdlaWdodD0iNzAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5QcnlzbSdzIHJlb3JnLXJhdGUgc3Bpa2VzIGFyZSBzb2xvPC90ZXh0PgogIDx0ZXh0IHg9IjkwMCIgeT0iMTA4IiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjE4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj43LWRheSBmbGVldCByYXRlcyDCtyBzYW1lIGhhcmR3YXJlIMK3IHNhbWUgY2hhaW4gwrcgbm8gb3RoZXIgY291bnRlciByZXNwb25kczwvdGV4dD4KCiAgPHJlY3QgeD0iODMxIiB5PSIxODAiIHdpZHRoPSIxNTYiIGhlaWdodD0iNTQwIiBmaWxsPSIjN2MyZDEyIiBvcGFjaXR5PSIwLjE4Ii8+CiAgPHJlY3QgeD0iMTEzMCIgeT0iMTgwIiB3aWR0aD0iMzM1IiBoZWlnaHQ9IjU0MCIgZmlsbD0iIzdjMmQxMiIgb3BhY2l0eT0iMC4xOCIvPgoKICA8dGV4dCB4PSI5MDkiIHk9IjE3MCIgZmlsbD0iI2ZiOTIzYyIgZm9udC1zaXplPSIxNCIgZm9udC13ZWlnaHQ9IjcwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+U3Bpa2UgMSAofjE1aCk8L3RleHQ+CiAgPHRleHQgeD0iMTI5NyIgeT0iMTcwIiBmaWxsPSIjZmI5MjNjIiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iNzAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5TcGlrZSAyICh+MzZoKTwvdGV4dD4KCiAgPGcgc3Ryb2tlPSIjMzM0MTU1IiBzdHJva2Utd2lkdGg9IjEiPgogICAgPGxpbmUgeDE9IjE4MCIgeTE9IjE4MCIgeDI9IjE4MCIgeTI9IjcyMCIvPgogICAgPGxpbmUgeDE9IjE4MCIgeTE9IjcyMCIgeDI9IjE3MDAiIHkyPSI3MjAiLz4KICA8L2c+CgogIDxnIHN0cm9rZT0iIzFjMjY1NCIgc3Ryb2tlLXdpZHRoPSIwLjUiIHN0cm9rZS1kYXNoYXJyYXk9IjMgMyI+CiAgICA8bGluZSB4MT0iMTgwIiB5MT0iMjkwIiB4Mj0iMTcwMCIgeTI9IjI5MCIvPgogICAgPGxpbmUgeDE9IjE4MCIgeTE9IjQzMCIgeDI9IjE3MDAiIHkyPSI0MzAiLz4KICAgIDxsaW5lIHgxPSIxODAiIHkxPSI1NzAiIHgyPSIxNzAwIiB5Mj0iNTcwIi8+CiAgPC9nPgoKICA8ZyBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0iZW5kIj4KICAgIDx0ZXh0IHg9IjE3MCIgeT0iMTg0Ij4wLjAxMjwvdGV4dD4KICAgIDx0ZXh0IHg9IjE3MCIgeT0iMjk0Ij4wLjAwOTwvdGV4dD4KICAgIDx0ZXh0IHg9IjE3MCIgeT0iNDM0Ij4wLjAwNjwvdGV4dD4KICAgIDx0ZXh0IHg9IjE3MCIgeT0iNTc0Ij4wLjAwMzwvdGV4dD4KICAgIDx0ZXh0IHg9IjE3MCIgeT0iNzI0Ij4wLjAwMDwvdGV4dD4KICA8L2c+CiAgPHRleHQgeD0iNjAiIHk9IjQ1MCIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxNCIgZm9udC13ZWlnaHQ9IjYwMCIgbGV0dGVyLXNwYWNpbmc9IjEiIHRyYW5zZm9ybT0icm90YXRlKC05MCA2MCA0NTApIj5SRU9SR1MgLyBTRUMgKGZsZWV0KTwvdGV4dD4KCiAgPGcgZmlsbD0iIzk0YTNiOCIgZm9udC1zaXplPSIxMyIgdGV4dC1hbmNob3I9Im1pZGRsZSI+CiAgICA8dGV4dCB4PSIxODAiIHk9Ijc0NSI+ZGF5IDA8L3RleHQ+CiAgICA8dGV4dCB4PSIzOTciIHk9Ijc0NSI+ZGF5IDE8L3RleHQ+CiAgICA8dGV4dCB4PSI2MTQiIHk9Ijc0NSI+ZGF5IDI8L3RleHQ+CiAgICA8dGV4dCB4PSI4MzEiIHk9Ijc0NSI+ZGF5IDM8L3RleHQ+CiAgICA8dGV4dCB4PSIxMDQ4IiB5PSI3NDUiPmRheSA0PC90ZXh0PgogICAgPHRleHQgeD0iMTI2NSIgeT0iNzQ1Ij5kYXkgNTwvdGV4dD4KICAgIDx0ZXh0IHg9IjE0ODIiIHk9Ijc0NSI+ZGF5IDY8L3RleHQ+CiAgICA8dGV4dCB4PSIxNzAwIiB5PSI3NDUiPmRheSA3PC90ZXh0PgogIDwvZz4KICA8dGV4dCB4PSI5NDAiIHk9Ijc3NSIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxNCIgZm9udC13ZWlnaHQ9IjYwMCIgbGV0dGVyLXNwYWNpbmc9IjEiPjIwMjYtMDUtMTYgMTQ6MDAgVVRDICDihpIgIDIwMjYtMDUtMjMgMTQ6MDAgVVRDPC90ZXh0PgoKICA8cG9seWxpbmUgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMjJjNTVlIiBzdHJva2Utd2lkdGg9IjEuNiIgb3BhY2l0eT0iMC44NSIKICAgIHBvaW50cz0iMTgwLDcyMCAyMTUsNTY1IDI0MCw3MjAgMjcwLDU2NSAzMDUsNzIwIDMzNSw3MjAgMzYwLDU2NSAzOTUsNzIwIDQxMCw1NjUgNDM1LDcyMCA0NjAsNTY1IDQ5MCw3MjAgNTEwLDU2NSA1NDAsNzIwIDU2NSw1NjUgNTk1LDcyMCA2MjAsNTY1IDY1MCw3MjAgNjcwLDU2NSA2OTUsNzIwIDcyMCw0MjUgNzQ1LDcyMCA3NzAsNTY1IDc5NSw3MjAgODE1LDU2NSA4NDAsNzIwIDg2NSw3MjAgODkwLDU2NSA5MjAsNzIwIDk0MCw1NjUgOTcwLDcyMCA5OTUsNTY1IDEwMTUsNzIwIDEwNDAsNzIwIDEwNjUsNTY1IDEwOTUsNzIwIDExMjAsNTY1IDExNDUsNzIwIDExNzAsNTY1IDExOTUsNzIwIDEyMjAsNzIwIDEyNTAsNTY1IDEyODAsNzIwIDEzMDUsNTY1IDEzMzAsNzIwIDEzNTUsNzIwIDEzODAsNTY1IDE0MTAsNzIwIDE0MzUsNTY1IDE0NjAsNTY1IDE0ODAsNzIwIDE1MDAsNTY1IDE1MjUsNzIwIDE1NDUsNzIwIDE1NzUsNDIwIDE2MTAsNTY1IDE2NDUsNTY1IDE2NzUsNTY1IDE3MDAsNzIwIi8+CgogIDxwb2x5bGluZSBmaWxsPSJub25lIiBzdHJva2U9IiNjNGI1ZmQiIHN0cm9rZS13aWR0aD0iMS44IiBvcGFjaXR5PSIwLjk1IgogICAgcG9pbnRzPSIxODAsNzIwIDI0MCw2NTYgMzIwLDcyMCA0MTAsNzIwIDUwMCw3MjAgNTgwLDY1NiA2NDAsNzIwIDcyMCw3MjAgODAwLDcyMCA4ODAsNzIwIDk2MCw3MjAgMTA0MCw3MjAgMTEyMCw3MjAgMTIwMCw3MjAgMTI4MCw3MjAgMTM0MCw2NTYgMTM5NSw2NTYgMTQzMCw3MjAgMTQ4MCw2NTYgMTU0NSw3MjAgMTYxMCw2NTYgMTY0NSw3MjAgMTcwMCw3MjAiLz4KCiAgPHBvbHlsaW5lIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2Y5NzMxNiIgc3Ryb2tlLXdpZHRoPSIyLjgiCiAgICBwb2ludHM9IjE4MCw2ODAgMjEwLDY0OCAyNTAsNjEzIDI5MCw2NjUgMzMwLDY2NSAzNzAsNjY1IDQwNSw2NjUgNDQwLDYxMyA0NzUsNjY1IDUxMCw2NjUgNTUwLDY2NSA2MDAsNjY1IDY0MCw2NjUgNjgwLDYxMyA3MjAsNjY1IDc2MCw2NjUgODAwLDY2NSA4MzEsNTQ3IDg1NSw0MTkgODgwLDM5NyA5MDUsMzczIDkzMCwzNTEgOTYwLDM5NyA5OTAsNDI1IDEwMTUsNTQ3IDEwNDUsNjY1IDEwNzUsNTQwIDEwOTUsNjY1IDExMzAsNTEzIDExNjUsNTI0IDEyMDAsNDYwIDEyMzUsMjc5IDEyNjUsNDIwIDEyOTUsNDMxIDEzMzAsNDY3IDEzNjUsNDMxIDEzOTUsMzc1IDE0MjAsMzIzIDE0NDUsNDQwIDE0NjUsNzIwIDE0OTUsNzIwIDE1MTUsNTU5IDE1NDAsNzIwIDE1ODAsNzIwIDE2MTUsNzIwIDE2NTUsNjQxIDE2OTAsNzIwIDE3MDAsNzIwIi8+CgogIDxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE0MzAsIDE4MCkiPgogICAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjI2MCIgaGVpZ2h0PSIxMjAiIHJ4PSI1IiBmaWxsPSIjMWUyOTNiIiBzdHJva2U9IiM0NzU1NjkiIHN0cm9rZS13aWR0aD0iMSIvPgogICAgPHRleHQgeD0iMTQiIHk9IjI2IiBmaWxsPSIjYTViNGNmIiBmb250LXNpemU9IjEzIiBmb250LXdlaWdodD0iNzAwIiBsZXR0ZXItc3BhY2luZz0iMSI+TEVHRU5EPC90ZXh0PgoKICAgIDxsaW5lIHgxPSIxNCIgeTE9IjQ4IiB4Mj0iNDQiIHkyPSI0OCIgc3Ryb2tlPSIjZjk3MzE2IiBzdHJva2Utd2lkdGg9IjMiLz4KICAgIDx0ZXh0IHg9IjUyIiB5PSI1MiIgZmlsbD0iI2ZmZmZmZiIgZm9udC1zaXplPSIxNCI+UHJ5c20gKDEyIGhvc3RzKTwvdGV4dD4KCiAgICA8bGluZSB4MT0iMTQiIHkxPSI3NiIgeDI9IjQ0IiB5Mj0iNzYiIHN0cm9rZT0iI2M0YjVmZCIgc3Ryb2tlLXdpZHRoPSIyIi8+CiAgICA8dGV4dCB4PSI1MiIgeT0iODAiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMTQiPkxpZ2h0aG91c2UgKDEyIGhvc3RzKTwvdGV4dD4KCiAgICA8bGluZSB4MT0iMTQiIHkxPSIxMDQiIHgyPSI0NCIgeTI9IjEwNCIgc3Ryb2tlPSIjMjJjNTVlIiBzdHJva2Utd2lkdGg9IjIiLz4KICAgIDx0ZXh0IHg9IjUyIiB5PSIxMDgiIGZpbGw9IiNmZmZmZmYiIGZvbnQtc2l6ZT0iMTQiPkdldGggRUMgwrcgY2hhaW5fcmVvcmdfZXhlY3V0ZXMgKDI2IGhvc3RzKTwvdGV4dD4KICA8L2c+CgogIDxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE4MCwgODEwKSI+CiAgICA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTUyMCIgaGVpZ2h0PSIxMDAiIHJ4PSI2IiBmaWxsPSIjMWUyOTNiIiBzdHJva2U9IiMzMzQxNTUiIHN0cm9rZS13aWR0aD0iMSIvPgogICAgPHRleHQgeD0iMjAiIHk9IjI4IiBmaWxsPSIjZmRlNjhhIiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iNzAwIiBsZXR0ZXItc3BhY2luZz0iMSI+V0hBVCBUSEUgQ0hBUlQgU0hPV1M8L3RleHQ+CiAgICA8dGV4dCB4PSIyMCIgeT0iNTQiIGZpbGw9IiNhNWI0Y2YiIGZvbnQtc2l6ZT0iMTQiPlByeXNtJ3MgPHRzcGFuIGZvbnQtZmFtaWx5PSJNZW5sbywgbW9ub3NwYWNlIiBmaWxsPSIjZmZmZmZmIj5iZWFjb25fcmVvcmdzX3RvdGFsPC90c3Bhbj4gcmVnaXN0ZXJzIHR3byBzdXN0YWluZWQgc3Bpa2VzICgxNSBoIGFuZCAzNiBoKSByZWFjaGluZyA0w5figJM3w5cgaXRzIHF1aWV0IGJhc2VsaW5lLjwvdGV4dD4KICAgIDx0ZXh0IHg9IjIwIiB5PSI3OCIgZmlsbD0iI2E1YjRjZiIgZm9udC1zaXplPSIxNCI+TGlnaHRob3VzZSwgdGhlIG90aGVyIENDcywgYW5kIEdldGgncyBFQy1zaWRlIDx0c3BhbiBmb250LWZhbWlseT0iTWVubG8sIG1vbm9zcGFjZSIgZmlsbD0iI2ZmZmZmZiI+Y2hhaW5fcmVvcmdfZXhlY3V0ZXM8L3RzcGFuPiBzdGF5IGF0IHRoZWlyIHJlZ3VsYXIgcHVsc2UgcmF0ZSB0aHJvdWdob3V0IGJvdGggd2luZG93cy48L3RleHQ+CiAgPC9nPgoKICA8dGV4dCB4PSIxMDAiIHk9IjkzNSIgZmlsbD0iIzk0YTNiOCIgZm9udC1zaXplPSIxNCI+wqkgUm9ja0xvZ2ljIEdtYkggwrcgU3RlcmV1bUxhYnM8L3RleHQ+CiAgPHRleHQgeD0iMTcwMCIgeT0iOTM1IiBmaWxsPSIjOTRhM2I4IiBmb250LXNpemU9IjE0IiB0ZXh0LWFuY2hvcj0iZW5kIj5xdWVyeTogc3VtIGJ5IChjY19jbGllbnQpIChyYXRlKGJlYWNvbl9yZW9yZ3NfdG90YWxbMWhdKSkgwrcgcHJvbWV0aGV1cy1jb2xkPC90ZXh0Pgo8L3N2Zz4K" width="1800" height="950" class="img_ev3q"></p>
<p>We checked the obvious explanation first: a Prysm version change during the window. The Prometheus <code>cc_version</code> label held at <code>v7.1.3</code> continuously across all 6 Prysm hosts for the full 7 days. The spikes are not the artifact of a release.</p>
<p>We also cannot point to a corresponding mainnet event for either window. Public block explorers do not record deep reorgs in those periods, and our EC-side counters are quiet through them.</p>
<p>One hypothesis that fits the data: Prysm's <code>beacon_reorgs_total</code> may increment on every fork-choice head re-attribution, including transient ones that are subsequently re-overridden by the next attestation update, while the other CCs that share the metric name appear to increment only when a head change crosses some stability threshold. We have not audited any client's source to prove this. The observation is restricted to: Prysm spikes, others stay flat. Either way, <strong>a Prysm reorg-rate spike on its own is not evidence of a chain anomaly</strong>. It is consistent with the fork-choice loop chewing on late blocks under transient peering or attestation delay, with the increment policy determining whether the counter responds.</p>
<p>Prysm's instrumentation also shifts between releases. We previously tracked one such transition in detail in the <a class="" href="https://docs.stereumlabs.com/blog/prysm-version-7-1-1-and-7-1-2-comparison-resources">Prysm v7.1.1 vs v7.1.2 resource report</a>, where block-processing latency on one EC pairing changed by 78% across a single point release. A rerun of this reorg census against future Prysm releases could land in different places.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="reorg-depth-histograms-lodestar-vs-prysm">Reorg depth histograms: Lodestar vs Prysm<a href="https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients#reorg-depth-histograms-lodestar-vs-prysm" class="hash-link" aria-label="Direct link to Reorg depth histograms: Lodestar vs Prysm" title="Direct link to Reorg depth histograms: Lodestar vs Prysm" translate="no">​</a></h2>
<p>Two CCs in our fleet populate a reorg-depth histogram: Lodestar (via <code>beacon_fork_choice_reorg_distance_bucket</code>) and Prysm (via <code>reorg_depth_bucket</code>, a Prysm-specific name). The other four CCs do not export an equivalent series over the queried window. Lighthouse increments <code>beacon_reorgs_total</code> 167 times in 7 days but does not appear to populate the matching histogram. We mention it as an instrumentation observation, not a finding about Lighthouse's correctness.</p>
<p>Lodestar's histogram, summed 7-day rate per bucket (<code>sum by (le) (rate(beacon_fork_choice_reorg_distance_bucket[7d]))</code>):</p>
<table><thead><tr><th>Bucket (slots)</th><th style="text-align:right">Cumulative rate</th></tr></thead><tbody><tr><td>≤ 1.0</td><td style="text-align:right">0.0000</td></tr><tr><td>≤ 2.0</td><td style="text-align:right">0.000385</td></tr><tr><td>≤ 3.0 through ≤ 100.0</td><td style="text-align:right">0.000385 (no further weight)</td></tr><tr><td>+Inf</td><td style="text-align:right">0.000385</td></tr></tbody></table>
<p>Every observation Lodestar's histogram records sits in the 1–2 slot bucket. This is consistent with Lodestar evaluating candidate reorgs internally, classifying their distance, then declining to execute them. It lines up with the 324 <code>headBlockIsTimely</code> decline events on the same fleet over the same window.</p>
<p>Prysm's histogram, same 7-day rate:</p>
<table><thead><tr><th>Bucket (slots)</th><th style="text-align:right">Cumulative rate</th></tr></thead><tbody><tr><td>≤ 1.0</td><td style="text-align:right">0.0000</td></tr><tr><td>≤ 2.0</td><td style="text-align:right">0.000276</td></tr><tr><td>≤ 4.0</td><td style="text-align:right">0.000296</td></tr><tr><td>≤ 8.0</td><td style="text-align:right">0.000334</td></tr><tr><td>≤ 16.0</td><td style="text-align:right">0.000415</td></tr><tr><td>≤ 32.0</td><td style="text-align:right">0.001893</td></tr><tr><td>+Inf</td><td style="text-align:right">0.001893</td></tr></tbody></table>
<p>Prysm's distribution has weight all the way out to the 16–32 slot bucket. Mainnet did not see a deep canonical reorg in this window. Public explorers confirm the chain stayed within single-slot reorgs throughout, and Geth's EC-side counter agrees. So Prysm's <code>reorg_depth_bucket</code> is recording something that is <strong>not</strong> canonical-chain depth. More likely, it is the distance along Prysm's internal fork-choice graph from the previous head to a new one, including head transitions that were never canonical. That is a reasonable thing to measure, but it is not the same thing Lodestar is measuring.</p>
<p><strong>Two clients can both label a histogram "reorg depth" and be measuring different things.</strong> The bucket boundaries are themselves a hint about what each team expected to see. Lodestar's spec-aligned <code>1, 2, 3, 5, 7, 10, 20, 30, 50, 100</code> versus Prysm's <code>1, 2, 4, 8, 16, 32</code> reflect different priors about the distribution.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="lodestars-silent-counting-zero-reorgs-but-the-evaluation-pipeline-runs">Lodestar's silent counting: zero reorgs, but the evaluation pipeline runs<a href="https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients#lodestars-silent-counting-zero-reorgs-but-the-evaluation-pipeline-runs" class="hash-link" aria-label="Direct link to Lodestar's silent counting: zero reorgs, but the evaluation pipeline runs" title="Direct link to Lodestar's silent counting: zero reorgs, but the evaluation pipeline runs" translate="no">​</a></h2>
<p>Lodestar reports <code>beacon_reorgs_total = 0</code> across every host, every window. But Lodestar is not idle. In the same 7-day window the depth histogram (<code>beacon_fork_choice_reorg_distance_bucket</code>, covered above) does receive observations, and <code>beacon_fork_choice_not_reorged_reason_total{reason="headBlockIsTimely"}</code> accumulates 324 increments across the 6 Lodestar hosts (54 per host) and 50 increments on the single Lodestar supernode. Both series carry non-trivial weight; only the headline counter stays zero.</p>
<p>The reason label name lines up with the consensus specs' <code>should_override_forkchoice_update</code> helper (<a href="https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/validator.md" target="_blank" rel="noopener noreferrer" class="">validator spec</a>). The simplified flow:</p>
<ol>
<li class="">The validator sees a late block at the start of slot N+1.</li>
<li class="">It considers proposing on the parent of that late block instead of building on it (a "late-block reorg" override).</li>
<li class="">Safety checks run, including: is the head block timely enough that overriding it would not damage the chain?</li>
<li class="">If the head block is timely, the spec says do not override.</li>
</ol>
<p>The label name suggests Lodestar's counter increments on that branch, but we have not verified against the source. The 7-day data on every Lodestar host:</p>
<ul>
<li class=""><code>beacon_reorgs_total</code>: 0</li>
<li class=""><code>beacon_fork_choice_not_reorged_reason_total</code>: 54 per host (non-supernode) or 50 (supernode), all under the single label value <code>headBlockIsTimely</code>, no other reason labels populated</li>
<li class=""><code>beacon_fork_choice_reorg_distance_bucket</code>: populated, all observations in the 1–2 slot bucket</li>
</ul>
<p>Taken together, the three series show a CC that is actively running the late-block reorg evaluation pipeline (computing candidate distances, recording decline reasons) but declining to act on the result in this window. <strong>Lodestar's published metrics make it look like Lodestar never <em>executes</em> a reorg on mainnet.</strong> Whether that is a true statement about Lodestar's behavior or a missing increment on <code>beacon_reorgs_total</code> requires source-level confirmation, which we are requesting from the Lodestar team alongside this post. In the meantime, <strong><code>beacon_reorgs_total</code> is not a portable observability primitive across CCs</strong>: a Lodestar operator who alerts on it gets no signal at all.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="cross-client-reorg-alerting-cheat-sheet">Cross-client reorg alerting cheat sheet<a href="https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients#cross-client-reorg-alerting-cheat-sheet" class="hash-link" aria-label="Direct link to Cross-client reorg alerting cheat sheet" title="Direct link to Cross-client reorg alerting cheat sheet" translate="no">​</a></h2>
<p>For an operator runbook, by question:</p>
<p><strong>Did our CC re-attribute its head in the last 5 minutes?</strong>
Use <code>rate(beacon_reorgs_total[5m])</code>. Alert on sustained elevation, but only after re-baselining per CC and per EC pair. Ignore brief Prysm spikes and any reading on Lodestar.</p>
<p><strong>Did the EC see a canonical chain rewrite?</strong>
Use <code>chain_reorg_executes</code> on Geth only. Alert on any non-zero rate during sustained head movement. Treat a zero reading on Nethermind or Reth as an instrumentation gap, not as safety.</p>
<p><strong>How deep was the latest reorg?</strong>
Use <code>beacon_fork_choice_reorg_distance_bucket</code> if you run Lodestar, or <code>reorg_depth_bucket</code> if you run Prysm. Alert on histogram weight in buckets greater than 2 slots. Do not compare Lodestar's histogram to Prysm's; they record different things.</p>
<p><strong>Did the proposer-boost reorg path trigger?</strong>
Use <code>beacon_late_block_attempted_reorgs</code> on Prysm or <code>beacon_safe_reorgs_total</code> on Nimbus. Alert on sudden surges. Absence of the metric on the other CCs is not absence of the event.</p>
<p><strong>Why didn't the CC reorg when we expected it to?</strong>
Use <code>beacon_fork_choice_not_reorged_reason_total</code> on Lodestar (the only CC in our fleet that exports it). Alert on reason-label changes over time. Cross-client comparison is not possible with this metric today.</p>
<p>If you need a single rule that works across the fleet, use <code>rate(chain_reorg_executes[15m])</code> on Geth EC hosts, with per-host thresholds calibrated to that host's 90-day baseline. Geth is the only EC in our fleet whose counter both exists and increments.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-glamsterdam-and-epbs-may-change-reorg-accounting">How Glamsterdam and ePBS may change reorg accounting<a href="https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients#how-glamsterdam-and-epbs-may-change-reorg-accounting" class="hash-link" aria-label="Direct link to How Glamsterdam and ePBS may change reorg accounting" title="Direct link to How Glamsterdam and ePBS may change reorg accounting" translate="no">​</a></h2>
<p>The Glamsterdam hardfork is expected to enshrine proposer-builder separation (ePBS) via <a href="https://eips.ethereum.org/EIPS/eip-7732" target="_blank" rel="noopener noreferrer" class="">EIP-7732</a>. At time of writing (May 2026), it is still in devnet stabilization per the Ethereum Foundation's <a href="https://blog.ethereum.org/2026/04/10/checkpoint-9" target="_blank" rel="noopener noreferrer" class="">April 2026 Checkpoint</a>, with no fixed mainnet activation slot. Under ePBS, the slot gains an explicit commit-reveal cycle: the proposer commits to a builder-signed execution header in-slot, the builder reveals the payload, and a payload-timeliness committee (PTC) votes on whether the reveal arrived in time. If the PTC says no, the slot's execution payload is empty.</p>
<p>That mechanism creates new transient head states that today's reorg counters do not contemplate. We are not in a position to predict exact numbers, but two structural points are worth flagging now rather than after the fork ships:</p>
<ul>
<li class=""><strong>Whichever client increment policy you have today carries into Glamsterdam.</strong> A counter that increments on every fork-choice head re-attribution will see a higher post-Glamsterdam baseline than one that only increments on canonical rewrites. Operators should re-baseline alert thresholds after the fork, not before.</li>
<li class=""><strong>The CC-side counter becomes the operational signal.</strong> With execution payloads decoupled from proposer commitments, "the chain reorged" and "the execution payload changed" partially decouple. EC-side counters like <code>chain_reorg_executes</code> will under-report what a validator operator cares about, and the relevant counters move to the CC side and to relay/builder observability.</li>
</ul>
<p>The pre-Glamsterdam takeaway from our 90-day census: if you cannot answer "what does my client mean by reorg today," you will not be able to answer "did my client behave correctly under ePBS" once the fork lands.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="frequently-asked-questions-about-ethereum-reorg-monitoring">Frequently asked questions about Ethereum reorg monitoring<a href="https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients#frequently-asked-questions-about-ethereum-reorg-monitoring" class="hash-link" aria-label="Direct link to Frequently asked questions about Ethereum reorg monitoring" title="Direct link to Frequently asked questions about Ethereum reorg monitoring" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-does-prysm-report-more-reorgs-than-other-ethereum-consensus-clients">Why does Prysm report more reorgs than other Ethereum consensus clients?<a href="https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients#why-does-prysm-report-more-reorgs-than-other-ethereum-consensus-clients" class="hash-link" aria-label="Direct link to Why does Prysm report more reorgs than other Ethereum consensus clients?" title="Direct link to Why does Prysm report more reorgs than other Ethereum consensus clients?" translate="no">​</a></h3>
<p>Prysm's <code>beacon_reorgs_total</code> appears to increment on transient fork-choice head re-attributions in addition to canonical reorgs. The other CCs that share the metric name (Lighthouse, Teku, Nimbus, Grandine) appear to increment only when a head change persists. The cross-client gap shrinks from 7× over 7 days to 1.5× over 90 days, suggesting the bigger Prysm count comes from short-lived events the other counters smooth over. We have not verified this against source code.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="does-lodestar-really-not-reorg-on-the-ethereum-mainnet">Does Lodestar really not reorg on the Ethereum mainnet?<a href="https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients#does-lodestar-really-not-reorg-on-the-ethereum-mainnet" class="hash-link" aria-label="Direct link to Does Lodestar really not reorg on the Ethereum mainnet?" title="Direct link to Does Lodestar really not reorg on the Ethereum mainnet?" translate="no">​</a></h3>
<p>Lodestar's <code>beacon_reorgs_total</code> shows exactly zero across every host and every queried window. But Lodestar's depth histogram is populated and its <code>beacon_fork_choice_not_reorged_reason_total{reason="headBlockIsTimely"}</code> counter fires around 54 times per host per week (about every 3 hours per host). From outside, that looks like Lodestar evaluates candidate reorgs and declines to execute them. Source-level confirmation is pending from the Lodestar team.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="which-ethereum-execution-clients-export-a-prometheus-reorg-counter">Which Ethereum execution clients export a Prometheus reorg counter?<a href="https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients#which-ethereum-execution-clients-export-a-prometheus-reorg-counter" class="hash-link" aria-label="Direct link to Which Ethereum execution clients export a Prometheus reorg counter?" title="Direct link to Which Ethereum execution clients export a Prometheus reorg counter?" translate="no">​</a></h3>
<p>In our fleet: <strong>Geth</strong> (<code>chain_reorg_executes</code>, increments normally), <strong>Nethermind</strong> (<code>nethermind_reorganizations</code>, registered and scraped but never increments), <strong>Reth</strong> (<code>reth_blockchain_tree_reorgs</code>, same as Nethermind). <strong>Besu, Erigon, and Ethrex do not export a Prometheus reorg counter</strong> at all. Operators have to derive reorg events from logs. This patchy coverage is one of the operational consequences of Ethereum client diversity: the same observability question gets six different answers, and three of those answers are silence.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-should-i-alert-on-reorgs-across-different-ethereum-consensus-clients">How should I alert on reorgs across different Ethereum consensus clients?<a href="https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients#how-should-i-alert-on-reorgs-across-different-ethereum-consensus-clients" class="hash-link" aria-label="Direct link to How should I alert on reorgs across different Ethereum consensus clients?" title="Direct link to How should I alert on reorgs across different Ethereum consensus clients?" translate="no">​</a></h3>
<p>Per-host baselines, per CC × EC pair. A single fixed <code>rate(beacon_reorgs_total[5m])</code> threshold does not port between clients: the same EC behind two different CCs produces reorg counts that differ by 2–3×. For one EC-side rule that works fleet-wide, alert on <code>rate(chain_reorg_executes[15m])</code> for Geth hosts; the same metric does not exist on the other ECs. Skip alerting on Lodestar <code>beacon_reorgs_total</code> entirely. It is always zero.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="will-ethereums-glamsterdam-upgrade-change-reorg-counting">Will Ethereum's Glamsterdam upgrade change reorg counting?<a href="https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients#will-ethereums-glamsterdam-upgrade-change-reorg-counting" class="hash-link" aria-label="Direct link to Will Ethereum's Glamsterdam upgrade change reorg counting?" title="Direct link to Will Ethereum's Glamsterdam upgrade change reorg counting?" translate="no">​</a></h3>
<p>Probably yes. Glamsterdam is expected to enshrine proposer-builder separation (ePBS) via <a href="https://eips.ethereum.org/EIPS/eip-7732" target="_blank" rel="noopener noreferrer" class="">EIP-7732</a>, which introduces commit-reveal cycles and payload-timeliness committees. Those mechanisms create new transient head states that today's counters do not contemplate. Plan to re-baseline alert thresholds after the fork. EC-side counters like <code>chain_reorg_executes</code> will under-report what validator operators care about, since execution payloads decouple from proposer commitments under ePBS.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="methodology">Methodology<a href="https://docs.stereumlabs.com/blog/ethereum-reorg-accounting-across-consensus-clients#methodology" class="hash-link" aria-label="Direct link to Methodology" title="Direct link to Methodology" translate="no">​</a></h2>
<p>All queries ran against our <code>prometheus-cold</code> datasource over windows ending around 2026-05-26 12:00 UTC.</p>
<p>Per-CC family total:</p>
<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">sum by (cc_client) (increase(beacon_reorgs_total{cc_version!="unstable-465c727"}[7d]))</span><br></span></code></pre></div></div>
<p>Per-host averages divide each family's total by the live production-host count (6 NDC2 hosts per CC family; the <code>cc_version!="unstable-465c727"</code> filter excludes the two Grandine custom-image hosts from the comparison).</p>
<p>Per-pairing average per host:</p>
<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 by (cc_client, ec_client) (increase(beacon_reorgs_total{cc_version!="unstable-465c727"}[7d]))</span><br></span></code></pre></div></div>
<p>EC-side Geth counter:</p>
<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">sum by (ec_client) (increase(chain_reorg_executes[7d]))</span><br></span></code></pre></div></div>
<p>Histogram bucket rates:</p>
<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">sum by (le) (rate(beacon_fork_choice_reorg_distance_bucket[7d]))</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">sum by (le, cc_client) (rate(reorg_depth_bucket[7d]))</span><br></span></code></pre></div></div>
<p>Lodestar's decline reason:</p>
<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">sum by (cc_client, reason) (increase(beacon_fork_choice_not_reorged_reason_total[7d]))</span><br></span></code></pre></div></div>
<p>Host counts as of 2026-05-26, taken from <code>count by (cc_client) (count by (cc_client, instance) (up{role="cc", job!="node_exporter"}))</code> and the EC equivalent. Filtering out <code>job="node_exporter"</code> is necessary because every CC and EC host runs node_exporter under the same <code>role</code> label, which otherwise double-counts.</p>
<ul>
<li class=""><strong>CC (NDC2)</strong>: Grandine 8 (6 stable v2.0.4 + 2 custom-image <code>unstable-465c727</code>), Lighthouse 6, Lodestar 6, Nimbus 6, Prysm 6, Teku 6.</li>
<li class=""><strong>CC supernodes (GCP)</strong>: one host per CC family.</li>
<li class=""><strong>EC (NDC2 + GCP)</strong>: Geth 13 (7 NDC2 + 6 GCP comparator), Besu 7, Erigon 6, Ethrex 6, Nethermind 6, Reth 6.</li>
</ul>
<p>The two Grandine custom-image hosts (<code>unstable-465c727</code>) are excluded from every comparison in the post; comparisons in this analysis run across the same 6 production hosts per CC family.</p>
<p>Lighthouse + Erigon shows up in the <code>up</code> query (two hosts), but <code>beacon_reorgs_total</code> returns no series for that specific pairing in the queried window. Likely an instrumentation or registration gap, not zero reorgs. Numbers in the per-pairing matrix divide totals by the matching <code>count(up)</code>, so pairings with missing counter series do not contribute to the comparison.</p>
<p>The 90-day window covers the post-Fusaka mainnet conditions only. Pre-Fusaka data (before December 3, 2025) is in cold storage but not included here because PeerDAS introduced sufficient changes to fork-choice timing that combining the two periods would mix populations. The <a class="" href="https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes">Fusaka hardware impact post</a> characterizes that boundary in detail.</p>
<p>Dashboard panel definitions for every metric used here are linked from the consensus-client dashboards in our public catalog at <a class="" href="https://docs.stereumlabs.com/docs/dashboards/list/catalog">/docs/dashboards/list/catalog</a>. The per-client dashboards on <a href="https://grafana.stereumlabs.com/" target="_blank" rel="noopener noreferrer" class="">grafana.stereumlabs.com</a> each carry the reorg panels described above. We do not yet ship a cross-client comparison dashboard for these metrics, so the cheat sheet above stands in for one.</p>
<p>If you operate one of the clients we measured and want to clarify what your counter actually measures (particularly the Lodestar <code>beacon_reorgs_total</code> definition and the Nethermind / Reth increment paths), write to <a href="mailto:contact@stereumlabs.com" target="_blank" rel="noopener noreferrer" class="">contact@stereumlabs.com</a>. We will append a correction with attribution.</p>]]></content:encoded>
            <category>client comparison</category>
            <category>reorgs</category>
            <category>observability</category>
            <category>Prysm</category>
            <category>Lodestar</category>
            <category>Lighthouse</category>
            <category>Teku</category>
            <category>Nimbus</category>
            <category>Grandine</category>
            <category>Geth</category>
            <category>Nethermind</category>
            <category>Reth</category>
        </item>
        <item>
            <title><![CDATA[StereumLabs introduced: the stack behind our Ethereum client measurements]]></title>
            <link>https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack</link>
            <guid>https://docs.stereumlabs.com/blog/stereumlabs-introduced-measurement-stack</guid>
            <pubDate>Wed, 20 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[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.]]></description>
            <content:encoded><![CDATA[<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>We run two Prometheus tiers:</p>
<ul>
<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>
<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>
</ul>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>Every metric series in <code>prometheus-cold</code> carries a fixed set of StereumLabs labels:</p>
<ul>
<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>
<li class=""><strong><code>ec_version</code></strong>: pinned version string.</li>
<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>
<li class=""><strong><code>cc_version</code></strong>: pinned version string.</li>
<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>
<li class=""><strong><code>deployment</code></strong>: provider code (<code>NDC2</code> for bare-metal Vienna, <code>GCP</code> for cloud).</li>
<li class=""><strong><code>location</code></strong>: provider-specific region or zone identifier.</li>
</ul>
<p>The result is that a query like</p>
<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>
<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>
<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>
<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>
<p>Neutral measurement is a methodological commitment, not a marketing claim. The concrete rules we enforce inside the fleet:</p>
<ul>
<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>
<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>
<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>
<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>
<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>
</ul>
<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>
<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>
<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>
<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>
<ul>
<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>
<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>
<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>
<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>
<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>
</ul>
<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>
<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>
<p>What matters is what the platform makes visible. A non-exhaustive recap of recent output:</p>
<ul>
<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>
<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>
<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>
<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>
<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>
<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>
</ul>
<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>
<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>
<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>
<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>
<p>The wiring looks like this:</p>
<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>
<p>A few properties of that loop that are worth being explicit about:</p>
<ul>
<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>
<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>
<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>
<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>
<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>
</ul>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>Three subscription tiers, structured around what we can responsibly support at each price point:</p>
<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>
<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>
<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>
<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>
<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>
<ul>
<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>
<li class=""><strong>Institutional node operators</strong> sizing infrastructure decisions against measurements taken at production-equivalent scale.</li>
<li class=""><strong>Researchers</strong> running cross-client studies who need a reproducible substrate that is documented down to the firmware version.</li>
<li class=""><strong>Security researchers and bug-bounty hunters</strong> using cross-client production observability to surface anomalies that source review alone misses.</li>
<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>
</ul>
<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>
<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>
<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>
<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>
<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>
<p>After that:</p>
<ul>
<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>
<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>
<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>
<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>
</ul>
<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>]]></content:encoded>
            <category>methodology</category>
            <category>observability</category>
            <category>StereumLabs AI</category>
        </item>
        <item>
            <title><![CDATA[Erigon's monolithic node: 25% faster execution, 2x slower commits]]></title>
            <link>https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos</link>
            <guid>https://docs.stereumlabs.com/blog/erigon-caplin-standalone-vs-classic-combos</guid>
            <pubDate>Wed, 13 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[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.]]></description>
            <content:encoded><![CDATA[<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>The first question is whether one binary holding two layers consumes more or less than two binaries holding one layer each.</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>Caplin sits in the upper-middle band, below the aggressive peer collectors (Grandine, Lodestar, Lighthouse) but well above the more conservative implementations.</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>The consensus side of Caplin exposes a different metric set than dedicated CCs, but the few metrics that exist look healthy:</p>
<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>
<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>
<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>
<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>
<p>Two operational properties of the standalone are real but not measurable from the outside.</p>
<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>
<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>
<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>
<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>
<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>
<p>That makes Caplin standalone a particularly good match for:</p>
<ul>
<li class=""><strong>Archive node operators</strong> wanting the smallest possible disk and CPU footprint for a complete node.</li>
<li class=""><strong>RPC providers</strong> prioritizing operational simplicity, predictable resource ceilings, and a single point of telemetry.</li>
<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>
<li class=""><strong>MEV searchers and analytics platforms</strong> consuming real-time chain state plus historical data.</li>
<li class=""><strong>Solo stakers</strong> who are comfortable accepting failure-domain coupling in exchange for a smaller hardware bill and simpler runbooks.</li>
</ul>
<p>It is less appropriate for:</p>
<ul>
<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>
<li class=""><strong>Operators with strict change-management policies</strong> that pin EL and CL upgrades on independent cadences, particularly during regression windows.</li>
<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>
</ul>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>]]></content:encoded>
            <category>client comparison</category>
            <category>engine API</category>
            <category>storage</category>
            <category>Erigon</category>
            <category>Caplin</category>
        </item>
        <item>
            <title><![CDATA[How Ethereum execution clients see the P2P network: a peering deep dive]]></title>
            <link>https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis</link>
            <guid>https://docs.stereumlabs.com/blog/ec-p2p-peering-behavior-analysis</guid>
            <pubDate>Wed, 06 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[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.]]></description>
            <content:encoded><![CDATA[<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>
<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>
<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>
<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>
<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>
<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>
<ul>
<li class="">How many peers does each EC maintain?</li>
<li class="">Who are those peers? What clients do they run?</li>
<li class="">How fast does each EC cycle through its peer set?</li>
<li class="">Does the consensus client you pair with your EC influence its P2P behavior?</li>
<li class="">What happens when DevP2P inbound ports are blocked?</li>
<li class="">What does all of this mean for Ethereum's network health?</li>
</ul>
<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>
<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>
<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>
<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>
<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>
<p>The first and most basic question: how many peers does each EC maintain?</p>
<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>
<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>
<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>
<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>
<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>
<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>
<p>The effect on peering is dramatic:</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>Besu exposes <code>besu_peers_peer_count_by_client</code>, giving us a full breakdown:</p>
<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>
<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>
<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>
<p>Ethrex exposes <code>ethrex_p2p_peer_clients</code> with more granular labels:</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>We checked peer counts per CC pairing across every EC on the fleet. The numbers are remarkably uniform:</p>
<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>
<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>
<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>
<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>
<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>
<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>
<p>Nethermind also logs the protocol version split among its peers, and Erigon reports its "GoodPeers" broken down by protocol:</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>The spread here is staggering: a factor of roughly 50,000x between the most and least churning clients.</p>
<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>
<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>
<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>
<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>
<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>
<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>
<ul>
<li class="">Besu's 24 peers are 75% Reth. Its Ethereum is a Reth-dominated network.</li>
<li class="">Ethrex's 105 peers are 43% Geth. Its Ethereum looks more like the "true" network composition.</li>
<li class="">Nethermind's view changes depending on which CC it runs with. One instance sees 70% Nethermind peers; another sees 37% Reth.</li>
<li class="">Erigon's protocol-level constraints give it a smaller effective peer set than its connection count suggests.</li>
<li class="">Reth casts the widest net (7,400 tracked peers, 130 connected) but aggressively rejects newcomers.</li>
</ul>
<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>
<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>
<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>
<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>
<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>
<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>
<p>This matters in concrete scenarios:</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>For comparison, the consensus layer's gossipsub mesh shows much better diversity. From our Lighthouse nodes' block gossip mesh:</p>
<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>
<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>
<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>
<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>
<p>Current approximate EC network shares (from ethernodes.org and clientdiversity.org, April 2026):</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<hr>
<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>
<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>
<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>
<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>
<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>
<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>
<li class=""><strong>Date of snapshot</strong>: April 29, 2026.</li>
</ul></div></div>]]></content:encoded>
            <category>client comparison</category>
            <category>networking</category>
            <category>client diversity</category>
            <category>Geth</category>
            <category>Nethermind</category>
            <category>Besu</category>
            <category>Erigon</category>
            <category>Reth</category>
            <category>Ethrex</category>
        </item>
        <item>
            <title><![CDATA[Blob performance across consensus clients]]></title>
            <link>https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients</link>
            <guid>https://docs.stereumlabs.com/blog/blob-performance-across-consensus-clients</guid>
            <pubDate>Wed, 29 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[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.]]></description>
            <content:encoded><![CDATA[<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>The lifecycle of a blob under PeerDAS:</p>
<ol>
<li class=""><strong>A rollup</strong> submits a transaction with blob data attached</li>
<li class=""><strong>The execution client</strong> receives the transaction and holds the blob in its blob pool</li>
<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>
<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>
<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>
</ol>
<p>Each of these steps has measurable performance characteristics, and they vary across consensus client implementations. That is what we measured.</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>All nodes run on identical bare-metal hardware in Vienna. Performance differences reflect client implementation, not infrastructure.</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>Teku and Grandine never need reconstruction. They collect their custody columns via gossip every time, consistent with their high processing success rates.</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>Two outliers:</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>🟢 = best in class · 🟠 = notable outlier · 🔴 = potential concern · †indirect via <code>peers_per_custody_group_count</code></p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>]]></content:encoded>
            <category>client comparison</category>
            <category>blobs</category>
            <category>PeerDAS</category>
            <category>Prysm</category>
            <category>Lighthouse</category>
            <category>Teku</category>
            <category>Nimbus</category>
            <category>Lodestar</category>
            <category>Grandine</category>
            <category>Reth</category>
            <category>Erigon</category>
        </item>
        <item>
            <title><![CDATA[Execution Client Sync Speed: From 1.5 Hours to 8+ Days]]></title>
            <link>https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026</link>
            <guid>https://docs.stereumlabs.com/blog/ec-sync-speed-comparison-april-2026</guid>
            <pubDate>Wed, 22 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[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.]]></description>
            <content:encoded><![CDATA[<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>Nethermind was the fastest client by a wide margin. Its container logs show a clean three phase sync:</p>
<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>
<p><strong>Phase 2, StateNodes (20:59 to 21:04, ~5min):</strong> World state download at the pivot point.</p>
<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>
<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>
<p><strong>Total: ~1 hour 22 minutes from cold start to processing live blocks.</strong></p>
<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>
<p>Erigon uses its unique staged sync pipeline. The <code>sync</code> Prometheus metric with per stage labels provides precise tracking:</p>
<ul>
<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>
<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>
<li class=""><strong>Finish stage:</strong> Reached the chain tip at ~08:40 UTC on April 9.</li>
</ul>
<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>
<p><strong>Total: ~13 hours.</strong></p>
<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>
<p>Besu performed a <strong>pivot based snap sync</strong> from block 0:</p>
<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>
<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>
<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>
<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>
<p><strong>Total: ~13h 15min to live operations, ~37h for complete historical data.</strong></p>
<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>
<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>
<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>
<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>
<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>
<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>
<p><strong>Total: 5 days 18 hours. Pipeline finished April 14, 13:47 UTC.</strong></p>
<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>
<p>Geth performed a snap sync from genesis with parallel header and state downloads:</p>
<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>
<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>
<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>
<p><strong>Snap sync complete: April 16, 10:32 UTC.</strong></p>
<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>
<p><strong>Total: ~7 days 15 hours. State healing was the multi day bottleneck.</strong></p>
<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>
<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>
<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>
<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>
<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>
<p>The sync had effectively restarted from scratch with minimal peer connectivity.</p>
<p><strong>Total: Not completed after 8+ days. The P2P snap sync is effectively stalled.</strong></p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<ul>
<li class="">All data sourced from Prometheus (<code>prometheus-cold</code> datasource) and Elasticsearch (Filebeat container log shipping) on the StereumLabs Grafana instance.</li>
<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>
<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>
<li class="">All nodes run on NDC2 bare metal hardware (Vienna), eliminating cloud induced variance.</li>
</ul>]]></content:encoded>
            <category>client comparison</category>
            <category>sync</category>
            <category>resources</category>
            <category>Geth</category>
            <category>Nethermind</category>
            <category>Besu</category>
            <category>Erigon</category>
            <category>Reth</category>
            <category>Ethrex</category>
        </item>
        <item>
            <title><![CDATA[Nimbus v26.3.1: Validator monitoring and block building across 5 execution clients]]></title>
            <link>https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building</link>
            <guid>https://docs.stereumlabs.com/blog/nimbus-v26-3-1-validator-monitoring-block-building</guid>
            <pubDate>Wed, 15 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[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.]]></description>
            <content:encoded><![CDATA[<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>Over 48 hours, block building was triggered for approximately 13 unique blocks. <strong>The results differ dramatically between execution clients.</strong></p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>The averages above compress a wide range of behavior into single numbers. Plotting every individual block build reveals the full distribution:</p>
<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>
<p>Three distinct patterns emerge:</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>Geth logged 214 payload updates and provides the clearest view of the block building lifecycle:</p>
<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>
<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>
<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>
<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>
<p>What Ethrex does log is an excellent per-block execution breakdown when processing incoming blocks:</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>Erigon's own logs show it actively attempts to build blocks but consistently fails to include transactions:</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>All 5 nodes should see roughly the same number of attestations for the monitored validators. Over 48 hours, they do not:</p>
<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>
<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>
<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>
<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>
<p>The 1,000 monitored validators' three Casper FFG vote types show dramatically different difficulty levels:</p>
<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>
<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>
<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>
<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>
<p>Over 48 hours, head vote accuracy shows a clear cyclic pattern:</p>
<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>
<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>
<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>
<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>
<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>
<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>
<p>Nimbus logs three key events per block building cycle:</p>
<ol>
<li class=""><code>Requesting engine payload</code> — timestamp, slot, beacon head, fee recipient</li>
<li class=""><code>Received engine payload</code> — full payload contents: gas_used, gas_limit, block_number, extra_data</li>
<li class=""><code>Block proposal included</code> — slot, validator ID</li>
</ol>
<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>
<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>
<p>An interesting infrastructure finding: the default log levels produce vastly different volumes across execution clients.</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<ol>
<li class="">
<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>
</li>
<li class="">
<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>
</li>
<li class="">
<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>
</li>
<li class="">
<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>
</li>
<li class="">
<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>
</li>
<li class="">
<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>
</li>
</ol>
<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>
<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>
<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>
<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>
<p>All nodes run on NDC2 bare-metal hardware (Vienna), eliminating cloud-induced variance.</p>
<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>]]></content:encoded>
            <category>client comparison</category>
            <category>block building</category>
            <category>validator duties</category>
            <category>engine API</category>
            <category>Nimbus</category>
            <category>Besu</category>
            <category>Erigon</category>
            <category>Ethrex</category>
            <category>Geth</category>
            <category>Nethermind</category>
        </item>
        <item>
            <title><![CDATA[Teku 25.12.0 vs 26.2.0 vs 26.3.0: Cross-version resource & performance analysis]]></title>
            <link>https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources</link>
            <guid>https://docs.stereumlabs.com/blog/teku-version-25-12-0-26-2-0-26-3-0-comparison-resources</guid>
            <pubDate>Wed, 08 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[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.]]></description>
            <content:encoded><![CDATA[<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p><strong>Metric:</strong> <code>rate(process_cpu_seconds_total{job="teku"}[5m])</code> — Teku JVM process CPU in CPU-seconds per second.</p>
<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>
<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>
<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>
<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>
<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>
<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>
<p><strong>Metric:</strong> <code>process_resident_memory_bytes{job="teku"}</code> — total physical memory consumed by the Teku JVM process.</p>
<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>
<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>
<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>
<p><strong>Metric:</strong> <code>jvm_memory_used_bytes{area="heap"}</code> — Java heap utilization.</p>
<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>
<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>
<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>
<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>
<p>Native (off-heap) memory rose modestly with RocksDB and stabilized with jemalloc.</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p><em>All values in KB/s.</em></p>
<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>
<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>
<p>These metrics are only available for versions using RocksDB. Version 25.12.0 ran LevelDB which does not expose equivalent counters.</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p><strong>Metric:</strong> <code>rate(beacon_data_column_sidecar_processing_requests_total[5m])</code> — DAS workload rate.</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<ol>
<li class="">
<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>
</li>
<li class="">
<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>
</li>
<li class="">
<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>
</li>
<li class="">
<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>
</li>
<li class="">
<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>
</li>
</ol>
<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>
<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>
<p>📄 <a href="https://docs.stereumlabs.com/downloads/teku_version_comparison_report.pdf" target="_blank">Download full report (PDF)</a></p>
<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>
<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>
<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>]]></content:encoded>
            <category>client comparison</category>
            <category>memory</category>
            <category>storage</category>
            <category>PeerDAS</category>
            <category>Teku</category>
        </item>
        <item>
            <title><![CDATA[EthCC[9] talk recap: AI-powered observability for Ethereum staking]]></title>
            <link>https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking</link>
            <guid>https://docs.stereumlabs.com/blog/ethcc9-talk-recap-ai-observability-ethereum-staking</guid>
            <pubDate>Thu, 02 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[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.]]></description>
            <content:encoded><![CDATA[<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>But dashboards have limits. And that's where AI comes in.</p>
<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>
<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>
<ul>
<li class="">"Compare disk growth between Geth and Erigon over the last 30 days"</li>
<li class="">"How did the Prysm update from v7.1.1 to v7.1.2 affect resource usage?"</li>
<li class="">"Which consensus client uses the most bandwidth as a supernode?"</li>
</ul>
<p>The result is a structured analysis with actual numbers, across all EL pairings, in seconds.</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>The same two-stage architecture applies to security events:</p>
<ul>
<li class=""><strong>SSH login checks</strong> — authorized key? Expected source IP? Expected time window?</li>
<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>
<li class=""><strong>Configuration drift detection</strong> — unauthorized processes, unexpected port openings, validator key access patterns.</li>
</ul>
<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>
<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>
<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>
<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>
<p>The fleet-level headline numbers:</p>
<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>
<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>
<p>The worst pairing post-fork: Nimbus + Reth at 16.78% CPU.</p>
<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>
<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>
<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>
<ul>
<li class=""><strong>SaaS</strong> — hosted by us in our ISO 27001 certified environment. Best for smaller operators and researchers.</li>
<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>
<li class=""><strong>On-premise</strong> — the entire StereumLabs stack deployed on your infrastructure. Your own API keys. Data never leaves your network.</li>
</ul>
<p>The key message: your infrastructure data doesn't become someone else's competitive intelligence.</p>
<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>
<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>
<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>
<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>
<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>
<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>
<p>The full slide deck from the talk is available for download:</p>
<p>📄 <a href="https://docs.stereumlabs.com/downloads/StereumLabs_EthCC9.pdf" target="_blank">Download slides (PDF)</a></p>]]></content:encoded>
            <category>talk recap</category>
            <category>observability</category>
            <category>security</category>
            <category>StereumLabs AI</category>
        </item>
        <item>
            <title><![CDATA[Fusaka hardfork: hardware impact on non-supernodes]]></title>
            <link>https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes</link>
            <guid>https://docs.stereumlabs.com/blog/fusaka-hardfork-hardware-impact-non-supernodes</guid>
            <pubDate>Mon, 30 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[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.]]></description>
            <content:encoded><![CDATA[<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>
<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>
<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>
<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>
<p>Beyond PeerDAS, Fusaka shipped approximately 12 additional EIPs:</p>
<ul>
<li class=""><strong>EIP-7935</strong> — raises the default block gas limit, targeting ~60 million gas</li>
<li class=""><strong>EIP-7825</strong> — introduces a per-transaction gas cap of 16.78 million to prevent single-transaction DoS attacks</li>
<li class=""><strong>EIP-7892</strong> — the Blob Parameter Only (BPO) mechanism, allowing blob capacity increases between hard forks</li>
<li class=""><strong>EIP-7951</strong> — secp256r1 precompile for device-native signing and passkeys</li>
<li class=""><strong>EOF (EVM Object Format)</strong> — a cleaner, more efficient programming structure for smart contracts</li>
<li class=""><strong>EIP-7918</strong> — stabilizes blob fees</li>
<li class=""><strong>EIP-7742</strong> — new opcodes including CLZ (count leading zeros) for more efficient cryptographic operations</li>
</ul>
<p>Two scheduled BPO forks followed:</p>
<ul>
<li class=""><strong>BPO-1</strong> (~December 9–10): blob target/max raised from 6/9 to 10/15</li>
<li class=""><strong>BPO-2</strong> (~December 23 – January 7): blob target/max raised to 14/21</li>
</ul>
<p>We wanted to know: what did all this actually do to the hardware running our nodes?</p>
<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>
<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>
<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>
<ul>
<li class=""><strong>Consensus clients:</strong> Grandine, Lighthouse, Lodestar, Nimbus, Prysm, Teku</li>
<li class=""><strong>Execution clients:</strong> Besu, Erigon, Ethrex, Geth, Nethermind, Reth</li>
</ul>
<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>
<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>
<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>
<p>We compared two 14-day windows:</p>
<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>
<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>
<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>
<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>
<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>
<p>Here's what happened across the entire non-supernode fleet:</p>
<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>
<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>
<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>
<p>Let's dig into each metric.</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>Network transmit bandwidth also decreased, though more modestly — from 0.20 to 0.18 MiB/s (−13%).</p>
<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>
<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>
<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>
<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>
<p>The daily time series reveals two notable spikes:</p>
<ul>
<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>
<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>
</ul>
<p>After settling, the new baseline sits around <strong>5.5–5.7%</strong> — roughly 1 percentage point above pre-fork levels.</p>
<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>
<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>
<p>Not all consensus clients handled Fusaka equally:</p>
<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>
<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>
<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>
<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>
<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>
<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>
<p>Execution clients saw a more uniform increase, consistent with the raised gas limit (EIP-7935) and new EVM opcodes (EOF):</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>The 14-day average still shows a net decrease because the early post-fork days pull the average down significantly.</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>Some notable per-pairing changes:</p>
<ul>
<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>
<li class=""><strong>lighthouse + reth</strong> dropped from 1.71 to 0.55 MiB/s (−68%)</li>
<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>
</ul>
<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>
<p>Disk writes increased <strong>11%</strong> — from 1.73 to 1.92 MiB/s. The increase is modest and likely comes from:</p>
<ol>
<li class=""><strong>PeerDAS sampling metadata</strong> — nodes now store sampling proofs and column indices</li>
<li class=""><strong>EOF state changes</strong> — the EVM Object Format introduces new bytecode validation and storage patterns</li>
<li class=""><strong>Higher gas limit</strong> — more transactions per block means more state writes</li>
</ol>
<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>
<p>This is a small overhead relative to the substantial read savings.</p>
<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>
<p>For the detail-oriented, here are the complete CPU and memory matrices across all CC×EC combinations.</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<hr>
<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>
<p>For reproducibility, here are the exact queries run against <code>prometheus-cold</code>:</p>
<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>
<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>
<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>
<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>
<p><strong>Datasource:</strong> <code>prometheus-cold</code> (UID: <code>aez9ck4wz05q8e</code>, Org 6)</p>
<p><strong>Before snapshot:</strong> instant query at <code>2025-12-03T00:00:00Z</code></p>
<p><strong>After snapshot:</strong> instant query at <code>2025-12-18T00:00:00Z</code></p>
<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>]]></content:encoded>
            <category>hard fork</category>
            <category>PeerDAS</category>
            <category>resources</category>
            <category>Geth</category>
            <category>Nethermind</category>
            <category>Besu</category>
            <category>Erigon</category>
            <category>Reth</category>
            <category>Ethrex</category>
            <category>Prysm</category>
            <category>Lighthouse</category>
            <category>Teku</category>
            <category>Nimbus</category>
            <category>Lodestar</category>
            <category>Grandine</category>
        </item>
        <item>
            <title><![CDATA[Prysm v7.1.1 & 7.1.2 resources]]></title>
            <link>https://docs.stereumlabs.com/blog/prysm-version-7-1-1-and-7-1-2-comparison-resources</link>
            <guid>https://docs.stereumlabs.com/blog/prysm-version-7-1-1-and-7-1-2-comparison-resources</guid>
            <pubDate>Wed, 25 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Let's have a look at both versions of Prysm 7.1.1 and 7.1.2 and it's resource consumption]]></description>
            <content:encoded><![CDATA[<p>Let's have a look at both versions of Prysm 7.1.1 and 7.1.2 and it's resource consumption</p>
<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>
<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>
<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>
<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>
<p><strong>Network connectivity was unaffected.</strong> Average libp2p peer count held at ~71 across both versions.</p>
<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>
<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>
<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>
<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>
<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>
<hr>
<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>]]></content:encoded>
            <category>client comparison</category>
            <category>memory</category>
            <category>resources</category>
            <category>Prysm</category>
        </item>
    </channel>
</rss>