Latency, and how it is measured
This page describes how latency is measured and reported. It does not state a target, a percentile or a promise, because CoRelayer has never run in production: there is nothing measured to publish, and a number that is not measured is not a number.
What sets the floor
Two facts of the network bound anything a relayer can do:
- Blocks arrive on a round. A transaction that misses the current round waits for the next one. Every millisecond of processing on our side is a fraction of a round's worth of risk that a transaction slips into the following one.
- There is a propagation grace. A transaction that has just arrived at a node is not selected immediately; it has to be seen for a short moment first. Best case is therefore the next round or the one after — not "instant".
Cross-shard execution adds its own step: the transaction executes in the sender's shard and its effect is carried to the receiver's shard.
A MultiversX round lasts about 600 ms. That is the network's own figure, not one CoRelayer measured.
Millisecond timestamps everywhere
Every time value in the API is Unix milliseconds as a JSON number, and the member name ends in
Ms. Seconds appear only where an external standard requires them — Retry-After,
RateLimit-Reset, a token TTL — and each of those has a millisecond twin in the body.
Two clocks are reported, and they are named so you never mix them:
| Source | Used for | |
|---|---|---|
chainTimeMs | The shard's block timestamp | Every entitlement decision and every ledger timestamp. |
serverTimeMs | Our wall clock | Request timestamps, lease expiry, clock-skew correction in clients. |
Entitlement is decided on chain time on purpose. Wall clocks drift and can be wrong; a block timestamp is a fact the whole network agreed on.
What is reported per transaction
Each relayed transaction carries a breakdown, all in milliseconds, all null when the underlying
timestamp is genuinely unknown rather than guessed:
| Field | Interval |
|---|---|
acceptToCosignMs | Received → relayer signature released |
cosignToBroadcastMs | Signature released → a gateway acknowledged |
addedMs | Received → acknowledged (the two above, together) |
inclusionMs | Received → the block that executed it |
finalityMs | Executed → final |
totalMs | Received → final |
roundsToInclusion | inclusionMs expressed in rounds |
crossShard | Whether the transaction crossed a shard boundary |
The first two are the part CoRelayer controls. Inclusion and finality are the network's.
Presenting them separately is the point: a service that reported only totalMs could hide its own
queueing inside the chain's variance.
Where you see it
| Per transaction | GET /v1/relay/{id}, and the Transactions screen of the dashboard. |
| Aggregated for your account | GET /v1/usage/latency, which reports p50, p95 and p99 — of your traffic. |
| Service-wide | GET /v1/status, and the status site. |
A percentile computed over your own transactions is a fact about what happened to you. It is not a forecast, and it is not an SLA. (Status and SLOs)
Why the relay call does not wait
POST /v1/relay answers as soon as the transaction is co-signed, or as soon as a gateway
acknowledges it — whichever the acknowledgement deadline allows. It never holds the connection open
until the transaction is in a block.
The reason is a safety property, not a performance one. A request that waits for inclusion turns every slow block into a client timeout, and a client that has timed out is a client that is about to build a second transaction for the same intention. Answering early and exposing the state through a stream removes that pressure entirely. (Delivery guarantees · Watch an intent)
What we will publish, when there is something to publish
Once an environment has run long enough to have a distribution rather than an anecdote, the measured numbers will appear on the status site and in the changelog, with the window they were measured over and the method. Every timing is measured on chain, never estimated: per shard, as percentiles over a stated window, with CoRelayer's own synthetic probes left out of the counts. Until then, this documentation says "designed for" where it has to describe an intention, and says nothing at all where it would otherwise be guessing.