<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: OpenChainBench</title>
    <description>The latest articles on DEV Community by OpenChainBench (@openchainbench).</description>
    <link>https://dev.to/openchainbench</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4036056%2F3c1f5331-fb19-4ab4-b370-0bec284c7557.png</url>
      <title>DEV Community: OpenChainBench</title>
      <link>https://dev.to/openchainbench</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/openchainbench"/>
    <language>en</language>
    <item>
      <title>Which cross-chain messaging protocol is actually fastest? An independent 2026 benchmark of Wormhole, LayerZero, Hyperlane, Axelar, and CCIP</title>
      <dc:creator>OpenChainBench</dc:creator>
      <pubDate>Mon, 27 Jul 2026 16:41:00 +0000</pubDate>
      <link>https://dev.to/openchainbench/which-cross-chain-messaging-protocol-is-actually-fastest-an-independent-2026-benchmark-of-1j4b</link>
      <guid>https://dev.to/openchainbench/which-cross-chain-messaging-protocol-is-actually-fastest-an-independent-2026-benchmark-of-1j4b</guid>
      <description>&lt;p&gt;The same cross-chain message can take 10 seconds or 25 minutes to deliver, depending on which chain you send it from and which messaging protocol you use. Same USDC value, same intent, roughly 150x difference in wall-clock time.&lt;/p&gt;

&lt;p&gt;If you build anything cross-chain in 2026, the choice between Wormhole, LayerZero, Hyperlane, Axelar, and Chainlink CCIP is often made by trust preference, ecosystem alignment, or which SDK your team already knows. Rarely does it come down to actual measured performance, because independent latency data across all five protocols has been hard to find.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmufhuzr8ozxuxyu8zge3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmufhuzr8ozxuxyu8zge3.png" alt=" " width="800" height="532"&gt;&lt;/a&gt;&lt;br&gt;
This post shares 24-hour rolling p50 medians for message delivery latency across all five, live from &lt;a href="https://openchainbench.com" rel="noopener noreferrer"&gt;OpenChainBench&lt;/a&gt; — an open-source benchmark platform that probes each protocol continuously from three regions.&lt;/p&gt;

&lt;p&gt;The finding that surprised me most: the dominant time cost is often the source chain's finality, not the messaging protocol itself. And the "fastest" protocol depends heavily on which source chain you route through.&lt;/p&gt;
&lt;h2&gt;
  
  
  What this benchmark measures
&lt;/h2&gt;

&lt;p&gt;OpenChainBench runs a Go harness that observes each protocol's public delivery events. For each message, it computes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Source-chain observation time&lt;/strong&gt; (when the source chain includes the message)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delivery time&lt;/strong&gt; (when the destination chain confirms receipt for LayerZero, Hyperlane, Axelar, and CCIP, or when the protocol reaches signing quorum for Wormhole VAAs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The delta is the latency. Every metric is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sampled every 60 seconds&lt;/li&gt;
&lt;li&gt;Aggregated as a 24-hour rolling p50 median&lt;/li&gt;
&lt;li&gt;Published under CC BY 4.0 licensing&lt;/li&gt;
&lt;li&gt;Open source — the harness is public Go code on GitHub&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No canary transactions, no synthetic traffic. Passive observation of live protocol usage. One consequence: routes with low traffic have smaller sample sizes and noisier percentiles. Sample sizes are visible on each live bench page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important caveat before comparing:&lt;/strong&gt; four of the five protocols (Hyperlane, LayerZero, Axelar, CCIP) are measured end-to-end (source → destination). Wormhole is measured only up to VAA quorum (source → Guardian 13-of-19 signatures), because destination-side relay is caller-driven and not intrinsic to the protocol. So Wormhole numbers understate full user-facing latency — the true end-to-end for a Wormhole message is quorum time plus destination relay time.&lt;/p&gt;
&lt;h2&gt;
  
  
  Hyperlane: fastest end-to-end at 10-22 seconds
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source chain&lt;/th&gt;
&lt;th&gt;Delivery p50 (24h)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Celo&lt;/td&gt;
&lt;td&gt;10.0 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Polygon&lt;/td&gt;
&lt;td&gt;10.3 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BNB Chain&lt;/td&gt;
&lt;td&gt;10.3 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Arbitrum&lt;/td&gt;
&lt;td&gt;10.5 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ink&lt;/td&gt;
&lt;td&gt;11.9 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unichain&lt;/td&gt;
&lt;td&gt;12.7 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sonic&lt;/td&gt;
&lt;td&gt;18.4 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Avalanche&lt;/td&gt;
&lt;td&gt;22.5 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Live: &lt;a href="https://openchainbench.com/benchmarks/hyperlane-message-latency" rel="noopener noreferrer"&gt;openchainbench.com/benchmarks/hyperlane-message-latency&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hyperlane delivers in 10 to 22 seconds across all 8 measured source chains — the tightest range of any protocol here. Even the slowest chain (Avalanche at 22.5 s) beats the fastest chain on LayerZero, Axelar, or CCIP.&lt;/p&gt;
&lt;h2&gt;
  
  
  LayerZero: 26-48 seconds
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source chain&lt;/th&gt;
&lt;th&gt;Delivery p50 (24h)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Monad&lt;/td&gt;
&lt;td&gt;26.2 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Robinhood Chain&lt;/td&gt;
&lt;td&gt;26.9 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Arbitrum&lt;/td&gt;
&lt;td&gt;31.5 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BNB Chain&lt;/td&gt;
&lt;td&gt;33.3 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Avalanche&lt;/td&gt;
&lt;td&gt;34.4 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Celo&lt;/td&gt;
&lt;td&gt;42.0 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sui&lt;/td&gt;
&lt;td&gt;45.0 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Solana&lt;/td&gt;
&lt;td&gt;48.3 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Live: &lt;a href="https://openchainbench.com/benchmarks/layerzero-message-latency" rel="noopener noreferrer"&gt;openchainbench.com/benchmarks/layerzero-message-latency&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;LayerZero delivers in 26 to 48 seconds — roughly 2 to 3 times slower than Hyperlane on comparable chains. Interesting anomaly: Arbitrum on LayerZero delivers end-to-end in 31.5 s, while Wormhole reaches quorum on Arbitrum in about 16 minutes (VAA-only, so the true Wormhole end-to-end is longer still). LayerZero's Ultra Light Node model uses different security assumptions than Wormhole's Guardian quorum, which explains the gap.&lt;/p&gt;
&lt;h2&gt;
  
  
  Wormhole: 5 seconds to 19 minutes (VAA quorum only)
&lt;/h2&gt;

&lt;p&gt;Reminder: Wormhole's benchmark measures only source-side VAA finalization to 13-of-19 Guardian quorum. Destination-side relay adds more time and is caller-driven.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source chain&lt;/th&gt;
&lt;th&gt;VAA finalization p50&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sui&lt;/td&gt;
&lt;td&gt;4.6 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monad&lt;/td&gt;
&lt;td&gt;5.2 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Berachain&lt;/td&gt;
&lt;td&gt;7.5 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Polygon&lt;/td&gt;
&lt;td&gt;7.6 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BNB Chain&lt;/td&gt;
&lt;td&gt;7.9 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Avalanche&lt;/td&gt;
&lt;td&gt;8.5 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ink&lt;/td&gt;
&lt;td&gt;10.0 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Injective&lt;/td&gt;
&lt;td&gt;12.5 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Solana&lt;/td&gt;
&lt;td&gt;18.5 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Moonbeam&lt;/td&gt;
&lt;td&gt;43.0 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ethereum&lt;/td&gt;
&lt;td&gt;14 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Arbitrum&lt;/td&gt;
&lt;td&gt;16 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unichain&lt;/td&gt;
&lt;td&gt;18 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Base&lt;/td&gt;
&lt;td&gt;19 min&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Live: &lt;a href="https://openchainbench.com/benchmarks/wormhole-vaa-latency" rel="noopener noreferrer"&gt;openchainbench.com/benchmarks/wormhole-vaa-latency&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two very different behaviors emerge. Non-Ethereum-finality chains (Sui, Monad, BNB, Solana) reach quorum in single-digit seconds. Chains that inherit Ethereum L1 finality (Ethereum, Arbitrum, Base, Unichain) wait 14 to 19 minutes. This is not Wormhole's design — Guardians refuse to sign until the source-chain state is finalized on Ethereum L1, which takes approximately two epochs (~13 min).&lt;/p&gt;
&lt;h2&gt;
  
  
  Axelar: 40 seconds on fast chains, 15+ min on Ethereum L2s
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source chain&lt;/th&gt;
&lt;th&gt;Delivery p50 (24h)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;BNB Chain&lt;/td&gt;
&lt;td&gt;40.6 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Osmosis&lt;/td&gt;
&lt;td&gt;47.2 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Polygon&lt;/td&gt;
&lt;td&gt;50.7 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Avalanche&lt;/td&gt;
&lt;td&gt;64.3 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Moonbeam&lt;/td&gt;
&lt;td&gt;95.1 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ethereum&lt;/td&gt;
&lt;td&gt;17 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Arbitrum&lt;/td&gt;
&lt;td&gt;20 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Base&lt;/td&gt;
&lt;td&gt;25 min&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Live: &lt;a href="https://openchainbench.com/benchmarks/axelar-gmp-latency" rel="noopener noreferrer"&gt;openchainbench.com/benchmarks/axelar-gmp-latency&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Same pattern as Wormhole. Fast on non-Ethereum-finality chains, slow on Ethereum-inheriting L2s. Base at 25 minutes is the slowest end-to-end measurement in this dataset.&lt;/p&gt;
&lt;h2&gt;
  
  
  Chainlink CCIP: 75 seconds to 17 minutes
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source chain&lt;/th&gt;
&lt;th&gt;Delivery p50 (24h)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;BNB Chain&lt;/td&gt;
&lt;td&gt;74.8 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Solana&lt;/td&gt;
&lt;td&gt;82.2 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Avalanche&lt;/td&gt;
&lt;td&gt;90.0 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monad&lt;/td&gt;
&lt;td&gt;92.0 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Polygon&lt;/td&gt;
&lt;td&gt;13 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ethereum&lt;/td&gt;
&lt;td&gt;17 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Robinhood Chain&lt;/td&gt;
&lt;td&gt;17.5 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optimism&lt;/td&gt;
&lt;td&gt;17.5 min&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Live: &lt;a href="https://openchainbench.com/benchmarks/chainlink-ccip-latency" rel="noopener noreferrer"&gt;openchainbench.com/benchmarks/chainlink-ccip-latency&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;CCIP is the slowest of the four end-to-end protocols measured, even on fast chains. This reflects Chainlink's more conservative security model — CCIP uses two independent risk-management systems that add latency but reduce trust assumptions.&lt;/p&gt;
&lt;h2&gt;
  
  
  The finality-depth choice: Polygon as a case study
&lt;/h2&gt;

&lt;p&gt;Same source chain, dramatically different delivery times depending on the protocol. Polygon illustrates this best:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;th&gt;Polygon delivery p50&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Wormhole (VAA quorum only)&lt;/td&gt;
&lt;td&gt;7.6 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hyperlane (end-to-end)&lt;/td&gt;
&lt;td&gt;10.3 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Axelar (end-to-end)&lt;/td&gt;
&lt;td&gt;50.7 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chainlink CCIP (end-to-end)&lt;/td&gt;
&lt;td&gt;13 min&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Polygon has the same actual finality time regardless of who observes it. The variance comes from what each protocol chooses to wait for. Hyperlane accepts Polygon at a lower confirmation depth. CCIP waits for a much deeper confirmation before signing, trading time for security. This is a protocol-level design choice, not a chain property.&lt;/p&gt;

&lt;p&gt;The takeaway for builders: even after picking your source chain, the protocol's finality-depth policy can multiply your delivery time by 100x. Fast finality is only fast if the protocol trusts it.&lt;/p&gt;
&lt;h2&gt;
  
  
  The finality tax
&lt;/h2&gt;

&lt;p&gt;Across every protocol, a consistent pattern emerges: chains that inherit Ethereum L1 finality (Ethereum, Arbitrum, Base, Optimism, Unichain) impose 14 to 25 minutes of waiting time regardless of which messaging protocol you use.&lt;/p&gt;

&lt;p&gt;This is not the protocol's fault. It is the source chain's finality guarantee.&lt;/p&gt;

&lt;p&gt;If your dApp originates cross-chain messages from Base and users complain the bridge is slow, no protocol change will fix it. The wait is in Ethereum L1 finality. The only way to meaningfully reduce it is to originate the message from a chain with faster finality (Sui, Monad, BNB Chain, Solana, Cosmos-adjacent chains).&lt;/p&gt;

&lt;p&gt;Conversely, choosing between Hyperlane, LayerZero, and Wormhole matters a lot on fast-finality chains where the messaging protocol itself becomes the bottleneck. On Sui, Wormhole reaches quorum in 5 seconds while other protocols take longer. On Celo, Hyperlane delivers end-to-end in 10 seconds while LayerZero takes 42 seconds. The differences compound depending on your source chain and the protocol's confirmation policy.&lt;/p&gt;
&lt;h2&gt;
  
  
  Which protocol should you use?
&lt;/h2&gt;

&lt;p&gt;Based on this dataset, a rough decision framework:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building on non-Ethereum-finality chains (Sui, Monad, BNB Chain, Solana, Avalanche, Cosmos-adjacent):&lt;/strong&gt;&lt;br&gt;
Hyperlane offers the tightest and fastest end-to-end latencies. Wormhole is competitive at the quorum step but the full end-to-end depends on destination-side relay. LayerZero is a middle option. Same-chain, cross-protocol deltas can be large (see Polygon above) — verify on the specific route you care about.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building on Ethereum L2s that inherit L1 finality (Arbitrum, Base, Optimism, Unichain):&lt;/strong&gt;&lt;br&gt;
Protocol choice is largely irrelevant for speed — you'll wait 14-25 min for finality regardless. Choose based on trust assumptions, ecosystem alignment, or which chain you're bridging to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building on Ethereum L1:&lt;/strong&gt;&lt;br&gt;
Same as above — expect a 14-17 minute latency floor imposed by L1 finality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building on Cosmos-adjacent chains (Osmosis, Injective, Celo):&lt;/strong&gt;&lt;br&gt;
Hyperlane is fastest at 10 s on Celo. Axelar is native to Cosmos SDK but slower (47 s on Osmosis).&lt;/p&gt;
&lt;h2&gt;
  
  
  How to reproduce these measurements
&lt;/h2&gt;

&lt;p&gt;OpenChainBench is fully open source. Every metric on the site is a Prometheus query against public data. You can reproduce any measurement locally.&lt;/p&gt;

&lt;p&gt;For Wormhole VAA finalization, the data source is the public wormholescan indexer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://api.wormholescan.io/api/v1/vaas?pageSize=100"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each VAA row includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;timestamp&lt;/code&gt; — source chain observation time&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;updatedAt&lt;/code&gt; — when wormholescan first indexed the VAA as fully-signed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The delta is the VAA finalization latency. OCB polls this endpoint every 60 seconds and computes rolling p50/p90/p99 percentiles.&lt;/p&gt;

&lt;p&gt;For the messaging protocols (Hyperlane, LayerZero, Axelar, CCIP), similar public event feeds exist. The Go harness for each is on GitHub, linked from each benchmark page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Full list of benchmarks: &lt;a href="https://openchainbench.com" rel="noopener noreferrer"&gt;openchainbench.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openchainbench.com/benchmarks/hyperlane-message-latency" rel="noopener noreferrer"&gt;Hyperlane message latency&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openchainbench.com/benchmarks/layerzero-message-latency" rel="noopener noreferrer"&gt;LayerZero message latency&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openchainbench.com/benchmarks/wormhole-vaa-latency" rel="noopener noreferrer"&gt;Wormhole VAA finalization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openchainbench.com/benchmarks/axelar-gmp-latency" rel="noopener noreferrer"&gt;Axelar GMP latency&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openchainbench.com/benchmarks/chainlink-ccip-latency" rel="noopener noreferrer"&gt;Chainlink CCIP latency&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Data license: CC BY 4.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All figures reflect 24-hour rolling p50 medians as of publication. Live dashboards update every 60 seconds — current numbers may differ. Each live dashboard is the authoritative source at any given moment.&lt;/p&gt;

&lt;p&gt;If you're building cross-chain and want a specific data point I didn't cover, ping &lt;a href="https://x.com/openchainbench" rel="noopener noreferrer"&gt;@openchainbench on X&lt;/a&gt; or check the live dashboards directly.&lt;/p&gt;

</description>
      <category>crypto</category>
      <category>blockchain</category>
      <category>web3</category>
      <category>performance</category>
    </item>
    <item>
      <title>Auto pick the cheapest cross chain bridge in Python with OpenChainBench</title>
      <dc:creator>OpenChainBench</dc:creator>
      <pubDate>Sun, 26 Jul 2026 06:13:01 +0000</pubDate>
      <link>https://dev.to/openchainbench/auto-pick-the-cheapest-cross-chain-bridge-in-python-with-openchainbench-5f2o</link>
      <guid>https://dev.to/openchainbench/auto-pick-the-cheapest-cross-chain-bridge-in-python-with-openchainbench-5f2o</guid>
      <description>&lt;h2&gt;
  
  
  Why bridge selection matters more than you think
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcxwc5gk6nhj3h8n978d8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcxwc5gk6nhj3h8n978d8.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you build a dapp that moves USDC across chains, you probably picked a bridge provider two years ago and never looked back. That decision is quietly costing your users money. Independent measurements show a fifteen times difference between the cheapest and the most expensive bridge on a $300 USDC transfer. NEAR Intents leads at 0.058 percent effective cost. deBridge trails at 0.897 percent. On a $10,000 transfer, that gap is roughly $84 out of your users' pockets for no additional service.&lt;/p&gt;

&lt;p&gt;This post walks through how to auto pick the cheapest bridge at runtime using OpenChainBench, a public benchmark that measures six major bridges every minute from three regions. The full leaderboard lives at &lt;a href="https://openchainbench.com/benchmarks/bridge-fee" rel="noopener noreferrer"&gt;https://openchainbench.com/benchmarks/bridge-fee&lt;/a&gt;. We look at two approaches. First, a plain REST call for classic dapps. Second, an MCP integration for AI agent workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach 1: Query the REST API from Python
&lt;/h2&gt;

&lt;p&gt;The benchmark exposes every ranking as JSON via a stable endpoint. No API key required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_cheapest_bridge&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return the name of the cheapest cross chain bridge right now.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://openchainbench.com/api/stat/bridge-fee&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;leader&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;leader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_cheapest_bridge&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cheapest bridge right now: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;leader&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cheapest bridge right now: Near Intents
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The endpoint returns the full ranking too, so you can route by health status or fall back if the leader is temporarily down.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rank_bridges&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://openchainbench.com/api/stat/bridge-fee&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;effective_cost_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;p50&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rankings&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;bridge&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;rank_bridges&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bridge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bridge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;effective_cost_pct&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; percent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Near Intents    0.058 percent
Relay           0.134 percent
Across          0.136 percent
Mobula          0.221 percent
LI.FI           0.423 percent
deBridge        0.897 percent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you have live data. Route your users through the cheapest available bridge and cache the result for five to ten minutes to avoid hammering the endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach 2: MCP integration for AI agents
&lt;/h2&gt;

&lt;p&gt;If you build an AI trading agent or a chatbot that helps users move funds, plain REST calls put the routing logic in your code. You want the LLM to reason about bridge selection dynamically based on context. That is where Model Context Protocol comes in.&lt;/p&gt;

&lt;p&gt;OpenChainBench exposes an MCP server that any MCP compatible client can consume. Claude Desktop, Cursor, and other MCP hosts can query the benchmark data natively through function calls, without you writing wrapper code.&lt;/p&gt;

&lt;p&gt;Register the server in your MCP client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add openchainbench https://openchainbench.com/api/mcp/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server exposes three tools: &lt;code&gt;list_benchmarks&lt;/code&gt;, &lt;code&gt;get_benchmark&lt;/code&gt;, and &lt;code&gt;query_prom&lt;/code&gt;. Once registered, your AI agent can answer questions like "which bridge is cheapest for a $300 USDC transfer from Solana to Base right now" by calling the tools directly, no extra plumbing needed.&lt;/p&gt;

&lt;p&gt;Example agent interaction:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;User: I need to move $500 USDC from Solana to Base. What is the cheapest option?&lt;/p&gt;

&lt;p&gt;Agent: Based on OpenChainBench live data, NEAR Intents is currently the cheapest at 0.058 percent effective cost (fees plus slippage plus destination gas). Relay is second at 0.134 percent. On $500, the difference is about $0.38 in your favor with NEAR Intents.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent pulls fresh data at query time, so it never quotes stale numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison of the two approaches
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;Setup effort&lt;/th&gt;
&lt;th&gt;Data freshness&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;REST API&lt;/td&gt;
&lt;td&gt;Classic dapps, backend routing&lt;/td&gt;
&lt;td&gt;5 minutes&lt;/td&gt;
&lt;td&gt;Real time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP server&lt;/td&gt;
&lt;td&gt;AI agents, chatbots, Claude Desktop&lt;/td&gt;
&lt;td&gt;2 minutes&lt;/td&gt;
&lt;td&gt;Real time&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Both approaches are free and require no API key. Data is published under CC BY 4.0.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Which cross chain bridge is currently the cheapest for USDC?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;NEAR Intents leads the OpenChainBench bridge fee bench at 0.058 percent effective cost for $300 USDC transfers across Solana, Base, and Arbitrum corridors. Relay is second at 0.134 percent, Across at 0.136 percent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does effective cost include?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The benchmark counts bridge fee plus exchange slippage plus destination gas required to finalize the transfer. Headline fee alone is misleading because bridges recoup margin through slippage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is the OpenChainBench API rate limited?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The public REST endpoint has generous limits sufficient for backend routing use cases. For high volume production, cache the ranking for five to ten minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I contribute a new bridge to the benchmark?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, the harness is open source at &lt;a href="https://github.com/ChainBench/OpenChainBench" rel="noopener noreferrer"&gt;https://github.com/ChainBench/OpenChainBench&lt;/a&gt;. Open an issue with the bridge you want added and the corridor to measure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the MCP server work with clients other than Claude Desktop?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, any MCP compatible client works: Cursor, Windsurf, generic MCP hosts, or custom LangChain and LlamaIndex agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Companion analysis
&lt;/h2&gt;

&lt;p&gt;For the editorial deep dive on why bridge markets are opaque and what it means for builders, see the companion piece on Substack:&lt;br&gt;
&lt;a href="https://substack.com/home/post/p-208526753" rel="noopener noreferrer"&gt;https://substack.com/home/post/p-208526753&lt;/a&gt;&lt;/p&gt;

</description>
      <category>crypto</category>
      <category>python</category>
      <category>defi</category>
      <category>api</category>
    </item>
    <item>
      <title>The Archive Multiplier: Why eth_call at a Historical Block</title>
      <dc:creator>OpenChainBench</dc:creator>
      <pubDate>Sun, 19 Jul 2026 15:38:59 +0000</pubDate>
      <link>https://dev.to/openchainbench/the-archive-multiplier-why-ethcall-at-a-historical-block-4c7g</link>
      <guid>https://dev.to/openchainbench/the-archive-multiplier-why-ethcall-at-a-historical-block-4c7g</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Passing a historical &lt;code&gt;blockNumber&lt;/code&gt; to &lt;code&gt;eth_call&lt;/code&gt;, &lt;code&gt;eth_getBalance&lt;/code&gt; or &lt;code&gt;eth_getLogs&lt;/code&gt; silently routes your request to the archive tier of hosted RPC providers. In our production metrics, archive calls cost on average &lt;strong&gt;26.7x more compute units&lt;/strong&gt; than the same call at &lt;code&gt;latest&lt;/code&gt;. This post explains why, shows the exact client code pattern that triggers it, and gives you three Prometheus queries to measure your own archive exposure in under a minute. Full cross provider measurements are published in the &lt;a href="https://openchainbench.com/benchmarks" rel="noopener noreferrer"&gt;OpenChainBench RPC benchmarks&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Last week our RPC cost dashboard flagged an overage projection above four thousand dollars for a single billing cycle on a single provider. On paper, our services were doing normal &lt;code&gt;eth_call&lt;/code&gt; operations. In practice, one small pattern buried in three separate indexers had multiplied our compute unit consumption by more than an order of magnitude, and nothing in the code review process had surfaced it.&lt;/p&gt;

&lt;p&gt;This post breaks down what an archive multiplier is, why it silently inflates blockchain RPC bills across every major hosted provider, and how to detect it in your own Prometheus stack before the next overage alert lands in Slack.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does "archive" mean at the Ethereum node level?
&lt;/h2&gt;

&lt;p&gt;Every request that reads the state of a smart contract, whether through &lt;code&gt;eth_call&lt;/code&gt;, &lt;code&gt;eth_getBalance&lt;/code&gt;, &lt;code&gt;eth_getStorageAt&lt;/code&gt;, &lt;code&gt;eth_getCode&lt;/code&gt;, or a batch of these, requires the RPC node to reconstruct the world state at a specific block height.&lt;/p&gt;

&lt;p&gt;Ethereum clients handle this in two modes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full node mode.&lt;/strong&gt; The state trie is kept in memory or on fast SSD for the tip of the chain plus a rolling window of recent blocks. On Geth default settings that window is 128 blocks deep. Any query targeting &lt;code&gt;latest&lt;/code&gt;, &lt;code&gt;pending&lt;/code&gt;, or a block within that window resolves in a few milliseconds against the current state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Archive node mode.&lt;/strong&gt; The client preserves every intermediate state trie since genesis. Answering a query at a block from months or years ago requires reading historical trie data off disk and reconstructing the state at that point. This is orders of magnitude slower and dramatically more storage intensive. A mainnet Ethereum archive node currently requires around twenty terabytes of NVMe storage. A full node runs on about one and a half terabytes.&lt;/p&gt;

&lt;p&gt;Hosted providers price this operational difference into their compute unit tables. The multiplier is not a bug in your billing. It reflects the real infrastructure cost of preserving all historical state.&lt;/p&gt;

&lt;h2&gt;
  
  
  The exact client code that triggers archive pricing
&lt;/h2&gt;

&lt;p&gt;A typical &lt;a href="https://viem.sh" rel="noopener noreferrer"&gt;viem&lt;/a&gt; call to read a token balance looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createPublicClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;viem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mainnet&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;viem/chains&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createPublicClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mainnet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RPC_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Path A, cheap: reads the current state.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readContract&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;erc20Abi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;balanceOf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;WALLET&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Path B, expensive: reads state at a specific historical block.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;historicalBalance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readContract&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;erc20Abi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;balanceOf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;WALLET&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;blockNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;18000000&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From a developer perspective the two calls are indistinguishable. Both return a &lt;code&gt;bigint&lt;/code&gt;. The &lt;code&gt;blockNumber&lt;/code&gt; parameter on the second call is what promotes the request to the archive tier on the provider side.&lt;/p&gt;

&lt;p&gt;In our codebase we found this pattern in five categories of code paths:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Token balance backfills&lt;/strong&gt; rebuilding historical wallet snapshots for analytics. Each snapshot iterates through blocks, calling &lt;code&gt;balanceOf&lt;/code&gt; at each snapshot point.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pool state reconstruction&lt;/strong&gt; for liquidity analytics, calling &lt;code&gt;getReserves()&lt;/code&gt; on Uniswap v2 pools or &lt;code&gt;slot0()&lt;/code&gt; on Uniswap v3 pools at every historical trade block.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bridge quote engines&lt;/strong&gt; that need the exact token balance and allowance at the source block when validating a cross chain transfer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Governance snapshots&lt;/strong&gt; replaying votes at a historical block to verify quorum.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit tools and debuggers&lt;/strong&gt; recomputing contract state at the block of a suspicious transaction to isolate the root cause of a bug.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these paths look expensive when you read them. They pass a single extra parameter to a familiar function call. But every one of those calls goes through the archive tier on the RPC provider.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Alchemy, Chainstack and QuickNode price archive requests
&lt;/h2&gt;

&lt;p&gt;Each provider publishes a compute unit or credit table in its public pricing documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alchemy&lt;/strong&gt; documents its compute unit weights in the &lt;a href="https://docs.alchemy.com/reference/compute-unit-costs" rel="noopener noreferrer"&gt;Alchemy compute units reference&lt;/a&gt;. The archive tier does not appear as a separate multiplier in the table itself. Instead, the archive rate applies once a request targets a block older than 128 blocks, and the effective cost per call in this mode is measured against the archive plan tier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chainstack&lt;/strong&gt; uses Request Units and prices archive traffic at approximately double the standard rate on shared nodes. Enterprise archive dedicated nodes have a flat pricing model instead of per request billing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;QuickNode&lt;/strong&gt; uses Credits per method. Archive calls carry a multiplier documented per method in the &lt;a href="https://www.quicknode.com/api-credits" rel="noopener noreferrer"&gt;QuickNode API credits reference&lt;/a&gt;, typically between two and five times the equivalent full node call.&lt;/p&gt;

&lt;p&gt;The observable behavior is consistent across all three. If you send the same request payload with and without a historical &lt;code&gt;blockNumber&lt;/code&gt; parameter, the request without it hits the fast path and the request with it hits a slower and more expensive path. On heavily loaded indexers this compounds fast, because each iteration of a backfill loop produces one archive request.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we measured on a production grade cluster
&lt;/h2&gt;

&lt;p&gt;We instrument every outbound RPC call in our services with a Prometheus counter carrying labels for provider, method, chain, and node type. Over a rolling 24 hour window on one chain that receives moderate traffic, the raw breakdown was as follows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Raw requests&lt;/th&gt;
&lt;th&gt;Compute units&lt;/th&gt;
&lt;th&gt;Effective ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;eth_call&lt;/code&gt; archive&lt;/td&gt;
&lt;td&gt;2,470,000&lt;/td&gt;
&lt;td&gt;65,970,000&lt;/td&gt;
&lt;td&gt;26.7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;eth_getLogs&lt;/code&gt; archive&lt;/td&gt;
&lt;td&gt;355,000&lt;/td&gt;
&lt;td&gt;9,500,000&lt;/td&gt;
&lt;td&gt;26.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;eth_getBalance&lt;/code&gt; archive&lt;/td&gt;
&lt;td&gt;49,200&lt;/td&gt;
&lt;td&gt;1,315,000&lt;/td&gt;
&lt;td&gt;26.7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;eth_call&lt;/code&gt; full&lt;/td&gt;
&lt;td&gt;4,000&lt;/td&gt;
&lt;td&gt;4,000&lt;/td&gt;
&lt;td&gt;1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The pattern is clean. Full mode calls average one compute unit per raw request. Archive mode calls on the same methods average close to twenty seven compute units per raw request. The ratio is stable across &lt;code&gt;eth_call&lt;/code&gt;, &lt;code&gt;eth_getLogs&lt;/code&gt;, and &lt;code&gt;eth_getBalance&lt;/code&gt;, which are the three read paths that carry the vast majority of our traffic.&lt;/p&gt;

&lt;p&gt;Translated into monthly cost on a moderately busy indexer on one chain, the archive share of that traffic drove roughly one thousand dollars of overage per month. Multiplied across five chains and three indexer instances, the number grows quickly into the tens of thousands per year.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to detect archive exposure with 3 Prometheus queries
&lt;/h2&gt;

&lt;p&gt;If you already record outbound RPC calls into a Prometheus counter, the following queries surface archive exposure in about thirty seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Query 1. Absolute compute units by node type over 24 hours:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sum by (node_type) (
  increase(rpc_compute_units_total{provider="alchemy"}[24h])
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Query 2. Archive share of total volume as a percentage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sum(rate(rpc_compute_units_total{provider="alchemy", node_type="archive"}[1h]))
/
sum(rate(rpc_compute_units_total{provider="alchemy"}[1h]))
* 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Query 3. Top ten source services and methods contributing to archive volume:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;topk(10,
  sum by (app, method) (
    increase(rpc_compute_units_total{provider="alchemy", node_type="archive"}[24h])
  )
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How to read the results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Below 5 percent archive share:&lt;/strong&gt; you are in good shape.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Between 5 and 20 percent:&lt;/strong&gt; a specific backfill or indexer is doing more archive reads than it needs to, and the top ten query above will point at the culprit within seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Above 50 percent:&lt;/strong&gt; archive is your primary traffic pattern and the cost curve is dominated by the multiplier rather than by request volume, which usually means a stalled or looping job.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you do not yet track this metric, the counter you want to add to your outbound HTTP transport takes labels for &lt;code&gt;provider&lt;/code&gt;, &lt;code&gt;method&lt;/code&gt;, &lt;code&gt;chain&lt;/code&gt;, and &lt;code&gt;node_type&lt;/code&gt;. Increment it once per response received, including 4xx and 5xx responses, because hosted providers bill errored calls just as they bill successful ones.&lt;/p&gt;

&lt;p&gt;For a full working example of this instrumentation across twenty two chains and three geographic regions, the &lt;a href="https://openchainbench.com/benchmarks" rel="noopener noreferrer"&gt;OpenChainBench RPC latency benchmarks&lt;/a&gt; publish the archive share of measured providers alongside p50, p95, and p99 latency. The instrumentation code that produces those metrics is open source &lt;a href="https://github.com/openchainbench" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt; and the full approach is documented on the &lt;a href="https://openchainbench.com/methodology" rel="noopener noreferrer"&gt;OpenChainBench methodology page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  5 strategies to reduce archive RPC costs in production
&lt;/h2&gt;

&lt;p&gt;Once you have detected the pattern in your own metrics, five interventions consistently cut archive cost in production without changing product behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Query at &lt;code&gt;latest&lt;/code&gt; when the caller has no reason to pin a block.&lt;/strong&gt; Audit every code path that passes a &lt;code&gt;blockNumber&lt;/code&gt; parameter to &lt;code&gt;readContract&lt;/code&gt;, &lt;code&gt;getBalance&lt;/code&gt;, or &lt;code&gt;getLogs&lt;/code&gt;. In a surprising fraction of cases the parameter was added defensively, without a functional requirement. Removing it drops the call from archive to full and eliminates the multiplier entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Cache archive responses aggressively.&lt;/strong&gt; An archive response for a finalized block is immutable. If your service asks for &lt;code&gt;eth_call&lt;/code&gt; at block 18000000 today and again next week, the two responses are byte for byte identical. Wrapping archive calls in a Redis or Postgres cache with a TTL measured in months collapses repeat calls to a single provider hit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Batch archive calls through Multicall3.&lt;/strong&gt; If an indexer needs one hundred &lt;code&gt;balanceOf&lt;/code&gt; reads at the same historical block, wrapping them in a single call to the &lt;a href="https://www.multicall3.com" rel="noopener noreferrer"&gt;Multicall3 contract&lt;/a&gt; at &lt;code&gt;0xcA11bde05977b3631167028862bE2a173976CA11&lt;/code&gt; reduces the provider side accounting to one archive request instead of one hundred.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Materialize derived state in your own datastore.&lt;/strong&gt; If your service repeatedly recomputes the same derived quantity from historical state, for example a token holder set at block N, write the result to your own Postgres or ClickHouse the first time and read from there for every subsequent access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Split archive traffic onto a provider with a lower multiplier.&lt;/strong&gt; The three providers price archive differently. If your workload is archive dominated, running a benchmark against Chainstack, QuickNode, and a self hosted archive node with the same request pattern will reveal cost differences worth thousands of dollars per month at production scale. The &lt;a href="https://openchainbench.com" rel="noopener noreferrer"&gt;live RPC provider comparisons on OpenChainBench&lt;/a&gt; publish latency and error rate data across those providers so you can weigh cost against performance before switching.&lt;/p&gt;

&lt;h2&gt;
  
  
  The observability gap in current web3 SDKs
&lt;/h2&gt;

&lt;p&gt;The reason this pattern persists in real codebases is that the archive tier is invisible from the SDK perspective. Viem, ethers, and web3.js expose &lt;code&gt;blockNumber&lt;/code&gt; as a routine parameter with no warning that it changes the pricing tier on the RPC side. The provider knows, the developer does not, and the metric never surfaces until the monthly bill arrives.&lt;/p&gt;

&lt;p&gt;Client side instrumentation with a &lt;code&gt;node_type&lt;/code&gt; label is currently the only reliable way to close this gap. If you already use an eRPC middleware or a custom HTTP transport wrapper, adding the label at request emission time takes about thirty lines of code. Once the label is in place, alerting on archive share crossing a threshold becomes a one line Prometheus rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is an archive node in Ethereum?&lt;/strong&gt;&lt;br&gt;
An archive node stores every intermediate state trie since the genesis block, which allows it to answer state queries at any historical block height. It requires roughly 20 TB of NVMe storage on mainnet, compared to about 1.5 TB for a full node.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does eth_call at a historical block cost more?&lt;/strong&gt;&lt;br&gt;
Because the node must read historical trie data from disk and reconstruct the world state at that block, instead of serving the query from the hot state kept in memory for recent blocks. Hosted providers pass that infrastructure cost through as a compute unit multiplier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How old does a block need to be to trigger archive pricing?&lt;/strong&gt;&lt;br&gt;
On most providers, any block older than the client's recent state window, which is 128 blocks on Geth default settings, is served from archive state and billed at the archive rate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How can I tell how much of my RPC bill comes from archive calls?&lt;/strong&gt;&lt;br&gt;
Instrument your outbound RPC transport with a Prometheus counter labeled by provider, method, chain, and node type, then compute the archive share with the queries in this article. Independent cross provider archive measurements are also published in the &lt;a href="https://openchainbench.com/benchmarks" rel="noopener noreferrer"&gt;OpenChainBench benchmarks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are archive responses safe to cache?&lt;/strong&gt;&lt;br&gt;
Yes, for finalized blocks. State at a finalized block is immutable, so responses can be cached indefinitely with no staleness risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;p&gt;The archive multiplier is not a design flaw of hosted RPC providers. It reflects the real cost of preserving twenty terabytes of historical state on hot storage and answering queries against it. The problem is that the mechanism is invisible from client code, so the cost accumulates behind an opaque call that looks routine in a code review.&lt;/p&gt;

&lt;p&gt;Three actions pay off immediately:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Instrument outbound RPC calls with a Prometheus counter that includes a &lt;code&gt;node_type&lt;/code&gt; label.&lt;/li&gt;
&lt;li&gt;Alert when the archive share of your total volume on any provider crosses five percent.&lt;/li&gt;
&lt;li&gt;Audit every code path that passes &lt;code&gt;blockNumber&lt;/code&gt; and either remove the parameter, cache the response, or batch through Multicall3.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once the three are in place, the next overage alert arrives with the root cause already visible in your dashboard rather than requiring an emergency investigation across five services and two Postgres replicas.&lt;/p&gt;

&lt;p&gt;If you want to see the full instrumentation applied to twenty two chains from three regions, &lt;a href="https://openchainbench.com" rel="noopener noreferrer"&gt;OpenChainBench&lt;/a&gt; publishes the live results under an open methodology, with data under a Creative Commons license and the harness source on GitHub.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://openchainbench.com/benchmarks/ethereum-rpc" rel="noopener noreferrer"&gt;OpenChainBench blog&lt;/a&gt;. Benchmarks, methodology and raw data are available at &lt;a href="https://openchainbench.com" rel="noopener noreferrer"&gt;openchainbench.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>web3</category>
      <category>blockchain</category>
      <category>sre</category>
    </item>
  </channel>
</rss>
