Activation notice — block 17,113,494
LIVE since block 17,113,494. Node 0.9.13 swapped in at block 17,113,493 on 2026-09-23, and both changes below turned on one block later. This page is the record of what changed at that boundary.
{"type":"account_state","address":"0x…"} carries the live height if you need to
check where the chain is.
Two behaviours move at this height. Anything else in the release changes no request, response, or rejection you can see.
Why one block above the swap. The outgoing node commits block 17,113,493 and only then halts, so that block still ran the old rules. The new rules apply from the first block after it.
The signed action is capped at 1 MiB
| Surface | Before the height | Now |
|---|---|---|
/exchange with an action over 1,048,576 bytes | Accepted when the whole body is under 2 MiB | 400 INVALID_REQUEST, message action is N bytes; the limit is 1048576 bytes |
node_actions error_code | No such code | DROPPED_ACTION_TOO_LARGE. Only a faulty proposer produces it |
/exchange with an action under the cap that does not fit one block | Accepted | Dropped before any block. The synchronous verdict is 200 INVALID_REQUEST, message action too large: its stored form does not fit in one block |
Why. Every validator stores the exact action bytes in the block and checks
the signature again at commit. The cap bounds the work that one action puts on
every validator.
What counts. The cap counts the action bytes as sent, whitespace included.
A compact 1,000-leg batch_order is between a quarter and a half of the cap.
The public endpoint refuses first. api.testnet.mtf.exchange refuses a
request BODY over 1 MiB with 413 and an HTML page, not the JSON envelope. An
action at the cap always makes a body over 1 MiB, so a caller on the public
endpoint sees that 413 and never the node's message. Match on the status, not
on a body you cannot parse.
Why an action under the cap can still fail. A block holds about 3 MiB. The node stores each action twice: the bytes as sent and the decoded action. A byte outside ASCII takes two bytes in that stored form. So only an action near the cap, made mostly of non-ASCII text, can be too large for one block.
What to do. Send compact JSON. Both client SDKs already do. Nothing else moves: every signing rule stays the same.
A batch_cancel answers for each leg
| Surface | Before the height | Now |
|---|---|---|
batch_cancel 200 reply | The admission fields only | The admission fields, plus statuses: one canceled or error entry per leg, in request order |
order_updates | No record for any batch_cancel leg | One status: "canceled" record per leg that removed its order. A refused leg pushes nothing |
Why. The legs run one by one, and a refused leg does not refuse the batch.
So before the height a node answered committed: true when a leg named an order
that was already gone, and the caller could not tell that leg from one that
removed its order. A leg that names the old oid of a modified order is the
common case.
What to do. Read statuses[i] for leg i. Match an error entry on
statuses[i].error.code: the entry is the flat {code, message, details?}
object, read on the running chain on 2026-09-23. Nothing else moves: the request shape, the signed digest and the
admission fields stay the same, so a caller that ignores statuses keeps
working.