The replay is the audit

Replay & verification

A match is recorded as its input-log and a sparse set of state-hash checkpoints. To verify, you re-run the same kernel over the same inputs and compare hashes — and a second, independent WebAssembly port must agree. Identity stamps are checked before a single tick is simulated, so mismatched engines are rejected instantly.

Determinism & math7 min read

A match is recorded as its inputs plus a sparse trail of state-hash checkpoints. To verify it, you re-run the same kernel over the same inputs and compare hashes — and a second, independent WebAssembly port must agree.

#The input-log is the record

The authoritative record of a match is small: the roster, and every signed shot in order. The client's WebAssembly prediction exists only for feel — it decides no rewards. When the two disagree, server truth wins and the client simply snaps to it. That inversion is the whole trick: you don't stream the game, you stream the inputs and recompute the game.

#Record and verify

Recording simulates the inputs until the board goes idle, capturing a checkpoint every 30 ticks — a quarter-second at 120 Hz. Verifying re-simulates the same inputs and compares each checkpoint; on a mismatch it reports the exact tick that first diverged.

record()
sim to idle, stamp a Checkpoint{tick, state_hash} every 30 ticks.
verify()
re-sim, compare each checkpoint, return first_divergence_tick on mismatch.
VerifyStatus
Ok · Diverged · SimVersionMismatch · ArenaHashMismatch.

#Identity stamps reject early

Every replay is stamped with the sim version and an arena hash. Before simulating a single tick, verify() checks those stamps — a mismatched engine version or a different board is rejected immediately, because comparing two different engines proves nothing. You can only audit like against like.

#The native ⇄ WASM parity gate

One C++ source is compiled to four targets — native, WASM-on-Node, Android and iOS — and run across a matrix of seeds. Each target folds every scenario's state hash into a single rollup hash, and the release gate is simple: all four must produce the identical rollup. If they don't, the build doesn't ship.

#What actually anchors on-chain

A hundred-player match is on the order of ten million ticks — it could never live in a transaction. So almost nothing does. Only a single 32-byte codex root lands on Solana: a Merkle root over the match header, the roster, each board, the signed shot-chain and the checkpoints. The full match is reproduced off-chain from the codex the root commits to, and anyone can check that the reproduction hashes back to the same root.