START

Performance, measured

10 ms blocks. About 3 ms per order. About 40 ms round trip. Every figure with its sample size, percentiles, origin and method.

An ephemeral rollup is described by three numbers: how often it makes a block, how long a transaction takes next to it, and how long a round trip takes over the network. Here are Interlude’s, each with its scope, because none of them holds everywhere. They come from audited runs on 2026-09-30, 12:55-13:30 and 17:12-17:34 UTC, on the build every production node has run since that day, which takes reads of Monad off the transaction path (the read-ahead build). Percentiles are nearest-rank; values are milliseconds as p50 / p95 / max unless a row says otherwise.

BLOCKS · ON THE NODE
10 ms
99.0-100.0 blocks a second on both Tap books and on Kandle's Paris, New York and Tokyo nodes. The California, Singapore, São Paulo and Johannesburg nodes run 82.5-94.0 a second.
ROWS 22
PER ORDER · NEXT TO THE NODE
~3 ms
A Tap order placed, cancelled or filled, send to receipt over a WebSocket, from a machine in the book's region: p50 2.4-4.1 ms by book and kind, 58-77 each. Signing excluded. The Paris book, with 77-106 resting orders, is the slower one. A Kandle tap takes 1.6-3.2 ms p50 on its seven tables.
ROWS 10, 27, 8
ROUND TRIP · OVER THE NETWORK
~40 ms
Warm round trip, client to node, on IPv6 (the default): p50 38.0-38.8 ms over WebSocket, 42.0 over HTTPS. On IPv4: 34.0 and 36.1-38.0. Requests enter Fly at Frankfurt. Timed end to end over the WebSocket: a Tap order 41.6-41.7 ms p50 (place, cancel, fill), a Kandle tap 39.7.
ROWS 4, 1, 2, 3, 13, 26, 12

What a call costs, and where the time goes

The node runs a transaction the moment it arrives and answers with the receipt and the return value in the same message (interlude_sendTransaction). The SDK sends it over a WebSocket it keeps open, so a call is one round trip; it falls back to HTTPS only after a lost WebSocket delivery, or where the runtime has no WebSocket (Node 20). The receipt is the node’s: Monad has the change at the node’s next commit, and a batch is final once its challenge window closes.

Next to the node, a call takes a few milliseconds. A Tap order placed, cancelled or filled takes 2.4-4.1 ms p50: a place 4.0 and a fill 4.1 on the Paris book, which held 77-106 resting orders, and 2.7 and 2.5 on the New York book. A crossing order fills inside the transaction that placed it, so the fill is in that transaction’s receipt. A GridBet call that reverts at once takes 2.3-3.0, and a Kandle tap 1.6-3.2 on its seven tables. What still reads Monad is the first transaction of a session, because slots keyed by an address are not read ahead: a join took 43.7-69.3 ms next to a Tap book, and 389.4-1387 on Kandle’s California, Singapore, São Paulo and Johannesburg tables, which sit 72-181 ms from Monad’s RPC.

Over the network, a round trip is about 40 ms: on IPv6, the default, 38.0-38.8 ms p50 over the SDK’s WebSocket and 42.0 over HTTPS; on IPv4, 34.0 and 36.1-38.0. Requests enter Fly at Frankfurt. Timed end to end, a Tap order took 41.7 ms p50 to place, 41.6 to cancel and 41.6 to fill, and a Kandle tap 39.7. A session’s first transaction costs more: a join on a Tap book took 83.6 ms p50. Across the Atlantic the network alone is about 110 ms. The first request on a cold connection costs 108.3-108.9 ms p50 on IPv6 (DNS cached, then TCP, TLS 1.3 and the request).

Next to Monad, not against it

A Monad transaction came back with its receipt in 305.2 ms p50 through Ankr and 369.5 through the public RPC, in one call (eth_sendRawTransactionSync). That receipt is Monad’s Proposed stage; Finalized came 858.5 ms p50 after the send. Monad testnet’s blocks are 303.8 ms apart on average. The two layers do different jobs: Interlude answers between blocks, and Monad settles, then finalizes, what Interlude commits. A round trip to an Interlude node and a Monad transaction are not the same measurement, so this page never divides one by the other.

Blocks

An Interlude node closes a block every 10 ms. Measured: 99.03 and 99.97 blocks a second on the Tap books in Paris and New York, and 99.04, 100.00 and 99.99 on Kandle’s Paris, New York and Tokyo nodes. Its California, Singapore, São Paulo and Johannesburg nodes run 82.5-94.0 a second. Why those four run slower is not established yet.

Kandle’s quick lock

Kandle prices a tap at the first Pyth tick stamped a set delay after its quoter saw the tap. In production, the lock is stored 400-646 ms p50 after the tap lands, by table (517 pooled over the seven, p95 1007), and the page sees it 462-673 ms p50 after sending, about 45 ms after it is stored, at its polling cadence. The quoter quoted every tap measured, and the page saw all but one inside its 1.5 s wait. When the quoter does not quote, the v3 fallback locks the tap at its reference print, and the page sees it after 2.8-3.9 s p50 by table.

What was measured

Kandle’s seven regional GridBet v3.1 tables, among them Paris 0x5B24…7480 at il2-eu-5b2476ebb7f253f3.fly.dev. Tap, the order book, in Paris (0x69b1…d5A6 at il2-eu-69b1ff7d02fb9fc4.fly.dev) and New York (0x1813…f83e). All on hub v3, Monad testnet.

The audited runs measured from a Mac, with client and node in the same region, and Fly machines in the nodes' regions (cdg, ewr, nrt, sjc, sin, gru and jnb). The round trips over the network come from the Mac, and the figures next to the node from the Fly machines. The Monad transactions come from an earlier run on the same Mac. The table gives each row’s origin.

The full table

  1. A Re-measured in the audited runs.
  2. R Reported by an earlier run, before the read-ahead build; method checked, not re-run.
  3. D Derived from other rows, not measured end to end.
  1. 01 · A

    Warm HTTPS round trip, Kandle Paris node (il2-eu-5b24…), IPv6 (the default)

    eth_call quote() 42.0 / 43.9 / 44.1 and 42.0 / 43.1 / 250.2 (two runs); eth_chainId 42.0 / 48.0 / 49.7 and 42.0 / 46.1 / 48.7. The auditor's re-run, eth_call: 41.9 / 46.1 / 53.9

    N
    60 per series per run, plus 30
    FROM
    Mac, client and node in the same region
    METHOD
    curl 8.7.1, HTTP/2, one process: 61 sequential POSTs on one connection (--next), the first dropped. Only transfers with no new connection and status 200 are kept, timed by time_total. Every fly-request-id ends in fra
    NOTE
    The 250.2 is one excursion on the Kandle node; its cause is not established
  2. 02 · A

    Warm HTTPS round trip, Tap Paris book (il2-eu-69b1…), IPv6

    eth_call midE6() 42.0 / 44.1 / 46.1 and 42.0 / 44.6 / 56.0 (two runs); eth_chainId 42.0 / 44.0 / 44.6 and 42.0 / 44.1 / 45.3. The auditor's re-run, eth_call: 42.0 / 44.0 / 44.0

    N
    60 per series per run, plus 30
    FROM
    Mac, client and node in the same region
    METHOD
    As row 1
  3. 03 · A

    Warm HTTPS round trip over IPv4 (curl -4)

    Kandle Paris: eth_call 38.0 / 39.8 / 700.8 and 37.8 / 38.1 / 39.1, eth_chainId 38.0 / 38.8 / 49.9 and 36.1 / 39.0 / 69.9. Tap Paris: eth_call 38.0 / 40.0 / 42.0 and 38.0 / 39.2 / 40.0, eth_chainId 38.0 / 40.5 / 54.1 and 38.0 / 39.2 / 41.9. The auditor's re-run: Kandle 36.1 / 38.2 / 42.3, Tap 38.0 / 39.9 / 40.0. p50 across every series: 36.1-38.0

    N
    60 per series per run, plus 30
    FROM
    Mac, client and node in the same region
    METHOD
    As row 1, with -4
    NOTE
    curl's time_total on this Mac lands on even milliseconds, so curl p50s move in 2 ms steps
  4. 04 · A

    Warm WebSocket round trip (the SDK's send transport), IPv6 (the default)

    Kandle Paris: eth_call 38.5 / 40.2 / 41.9, eth_chainId 38.8 / 41.5 / 42.0. Tap Paris: eth_call 38.2 / 40.9 / 42.8, eth_chainId 38.0 / 40.6 / 43.0. The auditor's re-run: Kandle eth_call 38.1 / 40.2 / 41.1, eth_chainId 38.0 / 40.0 / 40.0; Tap eth_call 38.0 / 40.1 / 41.4, eth_chainId 38.1 / 40.1 / 40.3. Over IPv4: p50 34.0 on all four series (the auditor's 33.9-34.0)

    N
    60 each, plus 30 each
    FROM
    Mac, client and node in the same region
    METHOD
    Node 20.20.2 WebSocket (undici), one socket per node, 5 unrecorded warm-ups per method, then sequential calls 50 ms apart, timed from send() to the matching message. IPv4 with --dns-result-order=ipv4first
    NOTE
    IPv6 costs about 4 ms more than IPv4, and a WebSocket is about 4 ms faster than curl. A browser run, earlier and not re-run: 40.0 / 41.9 / 61.5, n=60
  5. 05 · A

    Cold first request (cached DNS, then TCP, TLS 1.3 and the request)

    IPv6: p50 108.3-108.9, p95 113.1-115.4 over four series; pooled 108.6 / 114.1 / 1148.9. IPv4: p50 93.3-93.9, p95 97.0-98.2 over two series; pooled 93.7 / 97.8 / 102.4. At p50 on IPv6: DNS 1.9, TCP 29.4-30.1, TLS 34.1-34.3, the request 41.9-42.7. A WebSocket opens in 120.3 / 154.3 / 194.9 (Kandle) and 119.7 / 126.3 / 127.6 (Tap); open plus the first call, p50 158.8-159.6

    N
    60 per series (240 on IPv6, 120 on IPv4); 60 WebSocket opens per node
    FROM
    Mac, client and node in the same region
    METHOD
    60 separate curl processes 50 ms apart, --http2, a new connection on 60 of 60. WebSocket: a new socket each time, timed to open
    NOTE
    Not re-run by the auditor. Replaces the n=1 figures and the earlier run's quote
  6. 06 · A

    Where requests enter Fly

    Frankfurt (fra) on 1,591 of 1,591 requests from the Mac, WebSocket upgrades included, and 126 of 126 in the auditor's re-run; fra on 28 of 28 /health requests to the New York node. Fly machines enter at their own region (cdg, ewr or nrt), 60 of 60 per series

    N
    1,591 + 126 + 28
    FROM
    Mac, client and node in the same region; Fly machines in cdg, ewr and nrt
    METHOD
    fly-request-id suffix
  7. 07 · A

    CORS preflight on the node

    OPTIONS answers 200 with an empty body on both Paris nodes, bare and browser-shaped: allow-origin, -methods and -headers *; access-control-max-age 7200; vary: origin, access-control-request-method, access-control-request-headers; via 2 fly.io, 2 fly.io. No Timing-Allow-Origin, on the preflight or on the POST

    N
    6
    FROM
    Mac, client and node in the same region
    METHOD
    curl OPTIONS with Origin https://kandle.live
  8. 08 · A

    Kandle tapAt, send to receipt, in region, WebSocket

    All seven tables, 17:12-17:21 UTC: California 2.9 / 5.4 / 6.5, Singapore 3.0 / 5.5 / 7.5, São Paulo 1.6 / 2.3 / 4.2, Johannesburg 2.7 / 4.2 / 7.7, Paris 2.6 / 3.3 / 3.4, New York 2.4 / 6.1 / 7.0, Tokyo 3.0 / 4.8 / 7.4; pooled 2.7 / 4.8 / 7.7. The auditor's re-run: Paris 2.6 / 3.4 / 3.4, São Paulo 3.2 / 5.4 / 5.4. Earlier, 12:55-13:30 UTC: Paris 2.6 / 5.9 / 12.0 (runs 2.6 / 5.6 / 12.0, 2.4 / 5.9 / 6.4 and the auditor's 2.7 / 6.4 / 7.1), New York 2.8 / 4.7 / 12.4 (3.1 / 3.8 / 4.7 and 2.2 / 6.3 / 12.4), Tokyo 2.6 / 4.4 / 7.0 (2.1 / 2.7 / 5.3 and 2.8 / 4.9 / 7.0). The first tap of a fresh session, apart: 6.5-20.3 on Paris, New York, Tokyo and Singapore; California 81.8, São Paulo 148.7 (the auditor's 149.0), Johannesburg 186.5

    N
    40 per table (280), plus the auditor's 10 + 10; earlier Paris 80 (30 + 30 + 20), New York 60, Tokyo 60; 16 first taps
    FROM
    Fly machine (shared-cpu-1x) in the table's region (cdg, ewr, nrt, sjc, sin, gru, jnb)
    METHOD
    One sequential series of tapAt on a square the board offers, over a raw WebSocket (the SDK's frame), 1 chip, minMult 0 (as the page sends it), 0.8-1.4 s apart, signing excluded, the first dropped. Every tap landed with a Tapped event, none rejected. From 17:12 the page's own reads (rows 14 and 15) ran beside the taps on other sockets
    NOTE
    No serial read of Monad on any node (/health), one batched read per series: the session's first tap. São Paulo's 1.6 comes from one window; the auditor's 10 taps there gave 3.2. The far tables' figures from before the read-ahead build, which timed the serial reads it removed, stay withdrawn
  9. 09 · A

    A no-op GridBet transaction (join, which reverts AlreadySeated), in region, WebSocket

    Paris 2.3 / 3.1 / 5.0, New York 3.0 / 4.0 / 6.0, Tokyo 2.4 / 3.2 / 10.9, pooled; p50 by series 2.0-3.3

    N
    20 per series, the first kept: Paris 60, New York 40, Tokyo 40
    FROM
    Fly machine in the region
    METHOD
    As row 8, 150 ms apart
    NOTE
    São Paulo (14.1 in an earlier run) was not re-measured
  10. 10 · A

    Tap order placed or cancelled, in region, WebSocket

    Paris book: place 4.0 / 6.5 / 12.4, cancel 2.9 / 4.8 / 8.4 (p50 by series 4.0-4.1 and 2.9-3.6). New York book: place 2.7 / 3.3 / 6.5, cancel 2.4 / 4.0 / 6.1 (by series 2.1-2.8 and 1.9-2.7)

    N
    Paris 77, New York 58, of each kind, pooled over 2-3 series
    FROM
    Fly machine in the book's region (cdg or ewr)
    METHOD
    A bid of 10 at 0.50 rests and is cancelled at once, pairs 150-450 ms apart, over a raw WebSocket (the SDK's frame), signing excluded, the first dropped
    NOTE
    The Paris book held 77-106 resting orders, and a place used 0.89-1.16M gas; the New York book held only the probe's own orders, about 162k. Why Paris is slower is inferred from that, not proven; the node read nothing from Monad during any series. Orders over HTTPS were not re-measured (5.8-7.7 in an earlier run). Fills: rows 26 and 27. A session's first transaction: row 29
  11. 11 · R

    Node to Monad's RPC (testnet-rpc.monad.xyz), round trip

    Paris (cdg) 12.9 / 16.6 / 19.5, served from Frankfurt. p50 elsewhere: New York 8.4, Tokyo 4.8, California 72, Singapore 82, São Paulo 117, Johannesburg 181

    N
    30 per region
    FROM
    Fly machine in each region
    METHOD
    eth_getStorageAt at an old block, 150 ms apart
    NOTE
    Not re-measured. The read-ahead build added Ankr as a second read endpoint, so this row covers one of the node's two
  12. 12 · A

    Kandle tap over the network, send to receipt

    39.7 / 41.7 / 45.5 (two series: 39.5 / 41.6 / 41.7 and 40.9 / 43.4 / 45.5). The same-socket eth_chainId just before each tap: 39.5 / 40.8 / 43.7. Apart: the first tap of a session, 51.3 and 51.2

    N
    50 (30 + 20), 5 minutes apart
    FROM
    Mac, client and node in the same region, IPv6
    METHOD
    Node 20.20.2 WebSocket (undici), one send socket. withSession(tapAt(…)), 1 chip, minMult 0, signed by a session key before the clock starts; send() to the receipt message; taps 0.8-1.4 s apart, the first dropped. 50 of 50 landed with a Tapped event
    NOTE
    Was a prediction of about 80. The auditor's runs only. The table's keeper was paused, so the page's own fallback marks, one a second, kept the tape live
  13. 13 · A

    Tap order placed or cancelled, over the network, send to receipt

    Place 41.7 / 45.3 / 95.0 (series 41.5 / 44.7 / 45.2 and 42.4 / 46.7 / 95.0); cancel 41.6 / 44.2 / 109.4 (41.5 / 43.4 / 44.9 and 41.6 / 44.2 / 109.4). The same-socket eth_chainId just before each send: p50 38.1-39.6

    N
    78 of each, warm (two series of 40)
    FROM
    Mac, client and node in the same region (the Paris book), IPv6
    METHOD
    The SDK's send router (interlude_sendTransaction over a viem WebSocket), timed at ws.send and at the message event, signing excluded; one transaction in flight, 150-450 ms apart, the first dropped. The SDK's own send(), signing included, adds about 0.7
    NOTE
    Was a prediction of about 41-45. The 95-109 maxima fall in 13:06:08-22, when same-socket probes read 60-136 too: the Mac's side
  14. 14 · A

    Kandle's quick lock: lock stored after the tap landed

    Paris 400.4 / 973.8 / 1120.4, New York 447.8 / 840.7 / 992.8, California 494.6 / 646.6 / 983.6, Singapore 515.8 / 776.0 / 1007.2, São Paulo 543.9 / 922.2 / 1266.5, Johannesburg 581.0 / 1125.0 / 1365.1, Tokyo 646.1 / 1225.9 / 1607.4; pooled 517.3 / 1007.2 / 1607.4. The auditor's re-run: Paris 441.4 / 590.6 / 590.6, São Paulo 586.9 / 984.3 / 984.3

    N
    41 per table (287), plus the auditor's 11 + 11
    FROM
    Fly machine (shared-cpu-1x) in the table's region
    METHOD
    The taps of row 8. Tapped push to Locked push, both arriving on one interlude_subscribe("applied") socket (one clock). The auditor also read priceOf every 25 ms on its own socket: the last read that found no lock was sent 13-18 ms p50 before the Locked push, the first that found it 8-12 ms p50 after
    NOTE
    Every lock was the quoter's: 287 of 287 taps and 22 of 22 quoted. Timed from the send instead: pooled 521.9 / 1011.2 / 1612.0. The lock was below the multiplier at execution on 157 of the 287 and equal to it on 130. One window per table, n=41 each: the Tokyo and Johannesburg tails come from one series
  15. 15 · A

    Kandle's quick lock: seen by the page, at the page's poll cadence

    From the send: Paris 462.0 / 995.2 / 1129.5, New York 504.9 / 920.8 / 1039.2, California 550.8 / 766.0 / 1034.9, Singapore 578.6 / 853.9 / 1075.6, São Paulo 599.6 / 985.6 / 1360.7, Johannesburg 636.7 / 1311.5 / 1380.0, Tokyo 672.7 / 1325.6 / 2266.7; pooled 575.4 / 1046.2 / 2266.7. After the lock was stored: 44.8 / 94.4 / 654.7. The auditor's re-run: Paris 501.2 / 690.1 / 690.1, São Paulo 687.5 / 1006.7 / 1006.7

    N
    41 per table (287), plus the auditor's 11 + 11
    FROM
    Fly machine (shared-cpu-1x) in the table's region
    METHOD
    The page's own code (lib/quote.ts, lib/keeper.ts), wired as useBoard and useBeat wire it, on its own read socket: after the receipt a tapOf read, then priceOf every 100 ms, one round in flight, for 1.5 s; after that the one-second beat, which reads priceOf once the tape has reached the tap's reference second. Its heartbeat woke the keeper every 10 s. Timed from the send
    NOTE
    286 of 287 were seen inside the 1.5 s wait, and 22 of 22 in the auditor's. The other, a Tokyo tap, was quoted 1607.4 after it landed (the quoter's counters show one Tokyo tap found by its once-a-second poll, not pushed): its tile said "locking…", and the beat showed the lock at 2266.7, just after the reference print. The page's reads were made next to the node; from a browser, each also crosses the network (row 4)
  16. 16 · A

    The quoter's own counters (kandle-feed /quoter/<region>)

    tapToQuote p50 / p99 after each table's taps: New York 469 / 1099, Singapore 485 / 966, California 527 / 969, São Paulo 561 / 1362, Tokyo 640 / 1360, Johannesburg 646 / 1600; Paris 468 / 1600, 40 earlier taps included. tickAfterSeen p50 101-231. Its own lockQuoted send, per tap of this window: Paris 24 / 563 / 955 (min 6); p50 113-387 on the other tables, max 1205

    N
    41 per table, Paris 81; 287 sends
    FROM
    kandle-feed, in Paris (cdg), which quotes every table
    METHOD
    Public GET /quoter/<region> before and 12 s after each table's taps; counters since the quoter's restart at about 13:32 UTC. tapToQuote runs from when the quoter saw the tap to its lockQuoted receipt, tickAfterSeen from then to Pyth's stamp on the tick (two clocks). The sends are its recent list, which covered every tap
    NOTE
    Every table: ok and active, socket live, 41 of 41 quoted, none skipped, dropped or refused, no stalls. Its own round trip to each node (rttMs) read 23-406 from one read to the next. Paris's counters include 36 taps from 13:32-17:10 UTC and 4 from a smoke test
  17. 17 · A

    Kandle's lock when the quoter does not quote (the v3 fallback)

    Seen by the page, from the send: Singapore 2835.4 / 4113.4 / 4329.9, São Paulo 3089.2 / 4078.3 / 4560.7, California 3333.0 / 4285.1 / 4574.5, New York 3444.5 / 4268.8 / 5153.4, Paris 3484.6 / 4735.0 / 5049.4, Johannesburg 3780.8 / 5188.1 / 5309.8, Tokyo 3894.0 / 5066.1 / 5664.5; pooled 3423.9 / 4805.4 / 5664.5. A v3.1 page whose quote never comes: pooled 3419.7 / 4804.9 / 5663.2. The reference print, after the tap landed: 2879.2 / 4352.3 / 5657.6. The auditor's re-run (v3 page): Paris 3062.6 / 4628.9 / 4628.9, São Paulo 2862.5 / 4970.0 / 4970.0

    N
    41 per table (287), plus the auditor's 11 + 11
    FROM
    Fly machine (shared-cpu-1x) in the table's region
    METHOD
    No tap went unquoted, so the fallback was timed on the taps of row 14 by two page models on their own socket, running the page's code: a v3 page ("locking…" from the start; the beat reads priceOf once the tape reaches the tap's reference second) and a v3.1 page whose quote never comes (1.5 s reading lastTime against that second, then the beat). The reference print: Tapped push to the first Marked push at or past that second
    NOTE
    A model of the fallback, not a quoter switched off. The page marked as a page does when the tape was more than 2 s behind (28 marks, 10 on Johannesburg), so the keeper's lag on the far tables is in these times
  18. 18 · R

    A Monad transaction, send to receipt in one call (eth_sendRawTransactionSync)

    Ankr 305.2 / 435.3 / 508.1; public RPC 369.5 / 501.0 / 523.8

    N
    30 each
    FROM
    Mac, Paris
    METHOD
    A zero-value self-transfer, 21k gas, signed before the clock starts
    NOTE
    Not re-run in the audited run. The receipt comes at Monad's Proposed stage
  19. 19 · R

    A Monad transaction, send then poll for the receipt

    Public RPC 346.4 / 559.0 / 637.9; Ankr 430.4 / 605.1 / 923.4; all four paths pooled 364 / 562 / 923

    N
    30 each (120 pooled)
    FROM
    Mac, Paris
    METHOD
    Poll every 80 ms, so the time found is an upper bound
  20. 20 · R

    Monad: Finalized, after the send

    858.5 / 1033.6 / 1831.9

    N
    120
    FROM
    Mac, Paris
    METHOD
    monadNewHeads WebSocket events matched to the receipt's blockHash
  21. 21 · R

    Monad block time

    303.8 mean over the last 10,000 blocks; Proposed spacing 303.3 p50

    N
    10,000 / 847
    FROM
    Ankr / Mac, Paris
    METHOD
    Chain timestamps; WebSocket arrival times
  22. 22 · A

    Interlude blocks per second

    Kandle: Paris 99.04 (/health 98.99), New York 100.00, Tokyo 99.99; California 93.98 (94.03), Singapore 92.12, São Paulo 86.44, Johannesburg 82.64 (82.97). Tap: Paris 99.03 (99.06), New York 99.97 (100.02)

    N
    One 60 s window per node: 592-596 samples on the Paris nodes, 214-536 on the far ones, because calls were sequential over one WebSocket; 218-596 in the later window
    FROM
    Mac, and each node's /health
    METHOD
    Least-squares slope of eth_blockNumber against each call's send/receive midpoint; in parentheses, the ephemeralBlock delta on /health over the same window
    NOTE
    A second window on Kandle Paris, 13:02:53-13:05:53: 98.84. A later window on every node, 17:22:42-17:23:44 UTC: Kandle Paris 99.06, New York 99.96, Tokyo 100.00, California 93.74, Singapore 91.69, São Paulo 88.98, Johannesburg 82.50; Tap Paris 99.39, New York 100.00. During each Kandle table's taps (row 8), /health alone over 52-60 s: Paris 98.87, New York 99.95, Tokyo 99.79, California 92.93, Singapore 91.05, São Paulo 84.83, Johannesburg 79.96
  23. 23 · R

    The engine on a laptop (not production)

    interlude_sendTransaction 228 µs p50, 508 µs p95; eth_chainId 57 µs; about 3.1k tx/s for one client; a plateau at 2.8-3.1k tx/s

    N
    1,500
    FROM
    Mac loopback (M5 Pro) against anvil
    METHOD
    Release build of commit 772e66e
    NOTE
    Production throughput has never been measured
  24. 24 · R

    Commit costs on Monad, at 102 gwei

    A heartbeat: 153,759 gas = 0.0157 MON, about every 906 s. An awake Kandle table: 38.66 MON an hour. One player at about 5 taps a minute: 54.1 MON an hour. All in, about 0.046 MON per tap; the quick lock, about 0.0012 MON per tap

    N
    1,093 / 1,440 / 77 / 65 / 64
    FROM
    Ankr, on chain
    METHOD
    Receipts and balance deltas
  25. 25 · R

    What the measurement runs cost the validator (0xa375…eF43)

    326.80 MON at about 07:31 UTC, against 393.65 at 06:20: about 67 MON spent by the runs' own live tests

    N
    1
    FROM
    Ankr
    METHOD
    eth_getBalance
    NOTE
    Read in the morning's audited run. What this run cost was not measured in MON
  26. 26 · A

    Tap fill over the network, send to receipt

    41.6 / 45.4 / 99.3. The SDK path, two series: 41.5 / 43.6 / 44.5 and 43.5 / 45.4 / 99.3 (together 42.0 / 45.4 / 99.3). An independent raw-WebSocket client, the auditor's, filling against other makers' orders: 41.5 / 45.4 / 47.1. The same-socket network: p50 38.8-39.3

    N
    98 warm (78 + 20)
    FROM
    Mac, client and node in the same region (the Paris book), IPv6
    METHOD
    Market buys, market sells and limit orders at the best opposite price, in turn, 2 units at the top of a book of 90-110 resting orders; timed as row 13, signing excluded, the first dropped. 101 of 101 filled, each with exactly one Filled event
    NOTE
    The fill is in the receipt of the order that crossed, so it takes about what a place or cancel takes (row 13)
  27. 27 · A

    Tap fill in region: a crossing order that fills inside its own placing transaction

    Paris book, against the probe's own second seat: 4.1 / 8.2 / 16.9 (runs 3.9 / 6.6 / 11.0, 4.1 / 11.7 / 16.9 and the auditor's 4.2 / 8.2 / 8.2). Paris, against other makers' resting orders: 3.9 / 6.5 / 6.5. New York book, against its own maker: 2.5 / 4.8 / 15.0

    N
    Paris 77 (29 + 29 + 19) and 19; New York 58; warm
    FROM
    Fly machine in the book's region (cdg or ewr)
    METHOD
    As row 8, sent over the WebSocket. 170 of 170 filled
  28. 28 · A

    Tap fill to the New York book, from across the Atlantic

    117.3 / 120.1 / 122.7 (the clean series) and 115.6 / 416.3 / 417.5. The same-socket network: p50 109.9-111.8

    N
    40 each
    FROM
    The Mac of row 26, across the Atlantic from the book; requests enter Fly at fra
    METHOD
    As row 26. 80 of 80 filled
    NOTE
    One lens only. The second series' 7 samples at 414-418 came in two bursts, in the same seconds as spikes on the Mac's probes to the Paris nodes: the Mac's first hop, not the path or the node
  29. 29 · A

    First transaction of a new session (join)

    Over the network: Tap 83.6 / 85.4 / 85.5 against 39.0 of network, so about 45 on the node (one more, the auditor's: 99.0); Kandle 89.2 and 93.5. In region: Tap 48.2 / 69.3 / 69.3 (43.7-69.3), Kandle 18.1-80.6. Kandle's later window, one join per table: Paris 65.9, New York 47.1, Tokyo 40.4, California 442.7, Singapore 754.9, São Paulo 991.8, Johannesburg 1387; the auditor's Paris 53.9, São Paulo 389.4

    N
    Over the network 21 + 1 (Tap) and 2 (Kandle); in region 11 (Tap) and 7 + 7 + 2 (Kandle)
    FROM
    Mac, client and node in the same region; Fly machine in the node's region
    METHOD
    The first send of each fresh session key, timed as rows 26 and 8
    NOTE
    In the earlier window every join made exactly 2 batched reads of Monad (4 slots read ahead, 4 used, 0 serial): slots keyed by an address are not read ahead. The later joins were not broken down by read; the four far tables sit 72-181 ms from Monad's RPC (row 11)
  30. 30 · A

    Warm read round trip in region

    WebSocket eth_call: p50 1.3-2.4 (the auditor's, Paris: 1.7 on Kandle, 1.9 on Tap). HTTPS keep-alive eth_call: p50 2.3-6.3 (the auditor's 3.5 and 4.1)

    N
    60 per run; the auditor's 30
    FROM
    Fly machine in the node's region
    METHOD
    As rows 1 and 4, from the machine. The edge is the machine's own region on every request
    NOTE
    One Kandle sample in Paris took 896.9 (the next largest 7.8); its cause is unknown

Caveats the audit found

  1. 01

    IPv4 and IPv6 are different numbers

    In the same minutes, the same node answers a WebSocket call in 38.0 ms over IPv6 and 34.0 over IPv4, and an HTTPS call in 42.0 and 36.1-38.0. Both are right for their address family; compare within one.

  2. 02

    A read round trip is not a transaction

    The ~40 ms is the network. Next to the node, a Tap order adds about 2-4 ms and a Kandle tap about 3 (rows 8, 10 and 27). Setting a read round trip against a Monad transaction compares different things.

  3. 03

    The SDK's send path rarely pays a CORS preflight

    A preflighted HTTPS POST costs about two round trips, but the SDK sends over a persistent WebSocket by default and falls back to HTTP only after a lost WebSocket delivery, or where no WebSocket exists (Node 20). Over HTTP, the node now lets a browser keep the preflight for 7200 s, so only the first preflighted POST in that window pays the extra round trip.

  4. 04

    The Mac's first hop is in the tails

    Every p95 and max timed from the Mac depends on its Wi-Fi. A noisy window was measured and set aside; the table has the clean re-run. The 95-109 and 414-418 ms maxima of rows 13 and 28 fell in seconds when the Mac's other probes spiked too. Every order and tap from the Mac followed a read on the same socket, so these are warm figures: a page that sends after an idle gap may pay a Wi-Fi wake-up, which was not measured.

  5. 05

    Time on the node comes from the in-region rows

    Timing from the Mac is coarse: curl's clock lands on even milliseconds, and WebSocket times cluster. Subtracting the network from a Mac sample cannot resolve time on the node below about 2 ms, so the node's time is taken from rows 8, 10 and 27.

  6. 06

    Far tables pay for a session's first reads

    Warm, a Kandle tap takes the same few milliseconds on all seven tables (row 8). A session's first transactions still read Monad, and the California, Singapore, São Paulo and Johannesburg tables sit 72-181 ms from its RPC (row 11): there a join took 389.4-1387 ms and the first tap 6.5-186.5 (rows 29 and 8). These are single samples, one per table and run.

  7. 07

    Unexplained tails on the Kandle node

    5 of 1,020 samples from the Mac took 243-1149 ms, and one in region took 896.9. The node's lock wait stayed at most 0.06 ms and it made no serial read of Monad, so the cause is not established.

  8. 08

    Survivorship in the lock figures

    Rows 14 and 15 count only taps the quoter quoted, which was every tap: 287 of 287 on the seven tables and 22 of 22 in the auditor's re-run, each followed until its lock was seen, with no cap. 286 of the 287 were seen inside the page's 1.5 s wait. Since no tap went unquoted, row 17 comes from page models on the same taps.

  9. 09

    A parallel stress run is not a baseline

    One run tapped every region at once and overloaded the one shared keeper. It is left out of the table, and the later window tapped the tables one after another.

  10. 10

    The quoter's counters mix periods

    They start at the quoter's own 'seen' time, not at the tap's landing, and end at its lockQuoted receipt. Paris's include 40 taps from before the later window; the other tables' are that window's 41 each.

  11. 11

    Two clocks

    'Tick stamped after the tap landed' compares Pyth's clock with a Fly machine's clock, so it carries NTP-level error. Rows 14, 15 and 17 are each timed on one machine's clock.

  12. 12

    No single cold sample

    A cold first request measured once is not quoted; row 5's n=60 series are.

What this page does not claim

  • A Kandle tap, its lock or a Tap order timed from a browser. They were timed over the network from a Node client (rows 12, 13 and 26) or next to the node (rows 14-17); no browser figure was re-run.
  • ~40 ms from anywhere. It is the round trip with client and node in the same region; across the Atlantic the network alone measured about 110 ms (row 28).
  • 10 ms blocks on every node. They hold on the Paris, New York and Tokyo nodes and on both Tap books, not in California (93.7-94.0 a second), Singapore (91.7-92.1), São Paulo (86.4-89.0) or Johannesburg (82.5-83.0).
  • A Monad receipt as final. The receipt comes at the Proposed stage (305-370 ms p50); Finalized comes at about 860 ms p50; blocks are about 304 ms apart.
  • Interlude's receipt as settlement. It is the node's receipt, before the commit; Monad has the change at the next commit.
  • The laptop engine figures (row 23) as production latency or throughput. Production throughput has not been measured.
  • A cause for the read outliers, the slow far-region blocks or kandle-feed's slowness. The symptoms are measured; the causes are hypotheses.
  • Per-visit or per-day cost totals. They are models built on row 24, not measurements.

The same table is docs/PERFORMANCE.md in the repository. The trust side of the story is on What is live: v1 is permissioned, and Interlude holds every seat on the bench.