Limitsalpha
What is every hard number and bound in the system?
Every number on this page is a constant in this repository or a figure measured against mainnet, with its source named so you can re-check it. Where a bound is a decision rather than a measurement, the reason is in the source file's comment beside it — this page gives the value, not the argument.
Internet Computer limits the toolchain builds against#
These are the replica's, not moxzi's. They are what the on-chain compiler is engineered around; source: ic-limits-understanding.md, quoting dfinity/ic rs/config/src/subnet_config.rs.
| Bound | Value |
|---|---|
| Instructions per update message (with DTS) | 40 B |
| Instructions per DTS slice / round | 2 B |
| Instructions per round, subnet-wide | 4 B |
| Instructions per query | 5 B |
Instructions per install_code | 300 B |
| wasm64 instruction cost | 2 cycles/instruction (2× wasm32) |
| wasm32 heap / wasm64 heap | 4 GiB / 6 GiB |
wasm_memory_limit default | 3 GiB (exceeding it traps) |
| Stable memory | 500 GiB |
| Ingress payload | 2 MiB |
| Same-subnet inter-canister payload | 10 MiB |
| Chunk store | 1 MiB chunks, 100 chunks / 100 MiB |
| Heap-delta rate limit, per canister | 75 MiB dirtied per round |
Exceeding the message cap is not a moxzi diagnostic: the replica kills the canister with Canister exceeded the limit of 40000000000 instructions for single message execution (quoted at bin/compiler-canister/Main.mo:3848).
Compiler canister step budgets#
The on-chain compiler ends its own messages before the replica does. All in bin/compiler-canister/Main.mo.
| Constant | Value | Line |
|---|---|---|
onchainStepUnitBudget | 24 units per message | 3811 |
onchainStepInstrBudget | 6 B instructions per message | 3882 |
CONCLUDE_FRESH_START | 2 B — a conclude unit only starts below this | 3885 |
batchGarbageLimit | 1 GiB estimated garbage ends the batch | 3840 |
| Allocation ceiling per message | 16 MiB (rts_total_allocation delta) | 4209 |
Sched.defaultHeapGrowthLimit | 4 MiB growth since last yield | mops/mo-sched/src/Sched.mo:72 |
DEFAULT_CODEGEN_INSTR_BUDGET | 30 B | 1677 |
START_PARSE_WINDOW | 300 M, doubles on a no-progress message | 1704 |
MAX_PARSE_WINDOW | 30 B | 1682 |
On-chain build storage quotas#
| Store | Cap | Source |
|---|---|---|
| VFS, per caller | 64 MiB | vfsMaxBytesPerCaller, Main.mo:446 |
| VFS, all callers | 1 GiB | vfsMaxBytesTotal, Main.mo:447 |
| Content-addressed blob store | 256 MiB | blobStoreMaxBytes, Main.mo:960 |
| Whole-build cache | 200 MiB | buildCacheMaxBytes, Main.mo:1215 |
| Retained artifact | 100 MiB | retainedArtifactMaxBytes, Main.mo:3500 |
A caller over quota gets a trap naming the number, not a truncated upload. Files materialised from a mops tag are not charged against the VFS quota — they are references into the blob store.
Escrow pricing#
quoteEscrowFor(sourceBytes) = max(escrowCyclesFloor, sourceBytes × escrowCyclesPerByte).
| Constant | Value | Source |
|---|---|---|
escrowCyclesPerByte | 750,000 | Main.mo:2969 |
escrowCyclesFloor | 500 B cycles (0.5 T) | Main.mo:2970 |
| Settlement charge | 3× measured actual, remainder refunded | docs/onchain-builds.md |
Both are operator-settable. 750,000 is 3× the worst measured rate (200,657 cycles per source byte, the compiler compiling itself).
Measured on-chain builds#
Measured on mainnet, 2026-08-21 (docs/onchain-builds.md; hashes also on the site's proof table).
| Build | Source | Messages | Cycles | Artifact hash |
|---|---|---|---|---|
hello.mo | 1 file, 217 B | 52 | ~0.001 T | — |
| the compiler, self-compiling | 177 files, 8.0 MB | 2,345 | ~1.6 T | 830f3e87… |
evm_engine | 661 files, 15.3 MB | 4,138 | ~1.6 T/attempt | 178c6429… |
instructionsUsed under-reports real spend by 2.3×–3.4×. Do not price from it.
Parser depth#
| Bound | Value | Source |
|---|---|---|
MAX_PARSE_DEPTH (expressions and types) | 128 | mops/mo-frontend/src/Parser.mo:1176 |
Past it you get expression nested too deeply (limit 128) or type nested too deeply (limit 128) — a diagnostic, never a stack overflow. Gated by scripts/parser_depth_gate.sh, which fires a 600-deep operator chain and a 3000-deep type.
Browser stack#
Measured by scripts/web_page_compile_gate.sh (numbers in its header comment, lines 9–15 and 140–146).
| Quantity | JS-frame-equivalents |
|---|---|
| Compiler requirement, before the frame diet | ~13,759 |
| Compiler requirement, today | ~8,426 |
| A Chrome tab's main thread | ~11,154 |
| A worker | ~5,303 — smaller than a tab |
A worker is not a workaround for a stack problem. Separately, expression nesting is the binding constraint on generated code: ~60 chained operators compile in a tab, and past ~400 the limit moves into parsing (docs/limits.md).
moxzid request limits#
| Bound | Value | Source |
|---|---|---|
| Request body, authenticated endpoints | 64 MiB | MAX_BODY, moxzi/server/src/main.rs:1117 |
Request body, open /site gateway | 8 MiB | SITE_MAX_BODY, main.rs:1122 |
The /site cap is lower because that gateway has no bearer token in front of it.
moxzid execution defaults#
All settable on the command line; source moxzi/server/src/main.rs.
| Flag | Default |
|---|---|
--instruction-limit | 40,000,000,000 (0 disables) |
--cycles | 100 T (DEFAULT_CYCLES) |
--heartbeat-ms | 1000 |
--timer-ms | 100 |
--outcall-timeout-secs | 30 |
--history | 50 messages per actor |
--listen | 127.0.0.1:7000 |
Runtime caps shared by every runtime#
Both the native and browser backends use these constants so a program refused in one is refused in the other. Source moxzi/runtime/src/.
| Cap | Value | Source |
|---|---|---|
| Nested self-call depth | 512 | machine.rs:285 |
| Per-(sender, receiver) queue | 500 | sys.rs:301 |
| Retained log lines per actor | 4096 | sys.rs:45 |
| History argument preview | 128 bytes | machine.rs:1259 |
| Wasm stack (server and CLI) | 4 MiB | lib.rs:76, moxzi/src/main.rs:213 |
| Best-effort call deadline | capped at 300 s | sys.rs:803 |
Management-canister caps#
| Cap | Value | Source |
|---|---|---|
| Outcall response, when unspecified | 2 MiB | management.rs:344 |
| Chunk size | 1 MiB | management.rs:371 |
| Chunks per store | 100 | management.rs:377 |
| Snapshots per canister | 10 | management.rs:416 |
| Retained canister-change records | 20 | management.rs:30 |
wasm_memory_limit default | 4 GiB | management.rs:613 |
Off-chain cycle prices#
The off-chain runtimes bill with the IC's own formula so a program developed here does not under-attach on mainnet. Source moxzi/runtime/src/lib.rs and sys.rs.
| Item | Cycles |
|---|---|
| Per message | 590,000 |
| Per ten instructions | 4 |
| Canister creation | 500,000,000,000 |
| HTTP outcall, base | 400,000,000 |
| HTTP outcall, per byte | 100,000 |
| Threshold signature | 26,000,000,000 |
Things that are not bounded here#
| Not bounded | Consequence |
|---|---|
| Browser instructions | V8 has no fuel, so metering is opt-in instrumentation (meter: true): +16% to +20% module size, +49% run time on call-heavy code. Unmetered, preemption is a wall-clock worker deadline rather than a count |
| Off-chain storage growth | quotas exist on-chain only; a moxzid state directory grows until the disk says no |
| Number of moxzid processes | nothing coordinates two of them; each is a separate world |
Metering (browser instrumentation)#
Measured on 2026-08-21. Instrumentation is a host-side transform at install time; the compiled artifact is untouched, so byte-identity is unaffected.
| Quantity | Value |
|---|---|
Module size, counter.mo | +19.3% |
| Module size, the asset canister | +20.1% |
| Module size, the compiler itself (7.5 MB) | +15.8% |
| Run time, call-heavy code | +49% |
| Run time, a tight arithmetic loop (one basic block) | +87% |
| Default per-message limit | 40,000,000,000 instructions — the IC's own cap |
| Fuel global | __moxzi_fuel, exported, mutable i64, initialised to 0 |
The tight-loop figure is the worst case by construction: the loop body is the only basic block, so every charge also tests. Straight-line blocks charge without testing, because a block that cannot cycle only repeats a check the next loop header or function entry is about to do.
Source: moxzi/runtime/src/meter.rs, scripts/web_meter_gate.sh.
Next#
- Known differences — where these numbers make moxzi behave unlike a replica.
- Open questions — the bounds that are still arguments, not constants.
- The differential corpus — the sweeps that keep these numbers honest.