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.
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.
$ rr-test-lab run --seeds
- native
- 0x9671f5c32f16d0d2
- wasm-node
- 0x9671f5c32f16d0d2
- android-adb
- 0x9671f5c32f16d0d2
- ios-sim
- 0x9671f5c32f16d0d2
- verdict
- all targets agree ✓
#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.