nx_determinism.nx source
↩ module page · 70 lines · 2811 B
1// nx_determinism.nx -- rollback SYNC-TEST harness (GGPO "1-frame rollback
2// every frame"). PROVES simulation determinism instead of asserting it:
3// every frame, snapshot -> advance -> rollback to the snapshot -> re-
4// advance with the same input, and the re-simulated state checksum MUST
5// equal both the advanced state AND the no-rollback run. Any divergence
6// = a desync bug (the #1 rollback-netcode failure: state not captured in
7// the snapshot). Integer-only sims are deterministic by construction
8// (no float drift) -- this gate turns that structural property into a
9// gated, verified one.
10//
11// Composes nx_crc32c for the state checksum (CLAUDE.md 15). Sovereign.
12//
13// license_tier: ORIGINAL
14
15import "nx_crc32c.nx"
16
17func det_copy(dst: *i64, src: *i64, nwords: i64) -> i64 {
18 var i: i64 = 0
19 while i < nwords { dst[i] = src[i]; i = i + 1 }
20 return 0
21}
22func det_state_checksum(t: *i64, state: *i64, nwords: i64) -> i64 {
23 return crc32c_table(t, state as *u8, nwords * 8)
24}
25
26// A concrete DETERMINISTIC integer sim step (Q16.16-ish physics over an
27// entity array). Output depends ONLY on (state, input) -> deterministic.
28func det_sim_step(state: *i64, nwords: i64, input: i64) -> i64 {
29 var i: i64 = 0
30 while i < nwords {
31 state[i] = state[i] + input + (state[i] >> 3) + i
32 i = i + 1
33 }
34 return 0
35}
36
37// The GGPO rollback verifier. Returns the number of divergences (0 =
38// provably deterministic across rollbacks).
39func det_rollback_verify(t: *i64, state0: *i64, nwords: i64, inputs: *i64, nframes: i64) -> i64 {
40 let live: *i64 = sys_mmap(nwords * 8 + 16) as *i64
41 let save: *i64 = sys_mmap(nwords * 8 + 16) as *i64
42 let alt: *i64 = sys_mmap(nwords * 8 + 16) as *i64
43 let normal_ck: *i64 = sys_mmap(nframes * 8 + 16) as *i64
44
45 // 1) no-rollback reference run
46 det_copy(live, state0, nwords)
47 var f: i64 = 0
48 while f < nframes {
49 det_sim_step(live, nwords, inputs[f])
50 normal_ck[f] = det_state_checksum(t, live, nwords)
51 f = f + 1
52 }
53
54 // 2) per-frame save -> advance -> rollback -> re-advance, compare
55 var mism: i64 = 0
56 det_copy(live, state0, nwords)
57 f = 0
58 while f < nframes {
59 det_copy(save, live, nwords) // snapshot
60 det_sim_step(live, nwords, inputs[f]) // authoritative advance
61 det_copy(alt, save, nwords) // rollback
62 det_sim_step(alt, nwords, inputs[f]) // re-advance from snapshot
63 let ck_live: i64 = det_state_checksum(t, live, nwords)
64 let ck_alt: i64 = det_state_checksum(t, alt, nwords)
65 if ck_alt != ck_live { mism = mism + 1 } // rollback diverged
66 if ck_live != normal_ck[f] { mism = mism + 1 } // diverged from reference run
67 f = f + 1
68 }
69 return mism
70}