nx_frame_hash.nx
buildroot/runtime/nx_frame_hash.nx
about
nx_frame_hash.nx -- per-frame simulation-state hash for desync detection.
Purpose: across two or more clients running the same deterministic
simulation (RTS lockstep, fighting-game rollback, replay verifier),
each client computes a single i64 hash of its full sim state at the
end of every tick and exchanges it with peers. If hashes diverge,
the simulation has DESYNCED -- typically due to a determinism bug
(floating-point drift, unseeded RNG, OS-specific malloc behaviour).
Composes against nx_hash_fnv1a_bytes (FNV-1a 64-bit, public-domain).
The frame number is folded into the hash so two clients sampling
state at different frames never coincidentally match.
Sealed verdict (NxFrameHashVerdict) gives typed downstream action:
MATCH -- both clients agree on state hash AND frame
MISMATCH -- same frame, different hash -> DESYNC at this frame
FRAME_DIFF -- different frame numbers -> not comparable; resync
INVALID -- malformed input (e.g., negative length)
Source references:
- FNV-1a (Fowler/Noll/Vo, 1991, public domain): isthe.com/chongo/tech/comp/fnv/
- RTS lockstep desync detection: AoE GDC 2001 "1500 Archers"
- Rollback frame-hash exchange: GGPO `ggpo_synchronize_input` callback
genealogy_id: fnv1a_1991 + ggpo_desync_check + aoe2_lockstep_hashcheck
lineage_id: deterministic_sim_consensus_hash
dependencies 3 imports · 1 importers
imports: nx_syscalls.nxnx_tier.nxnx_hash.nx
imported by: nx_rollback_session.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 40 | const NX_FH_MATCH: nx_int = 0 |
| 41 | const NX_FH_MISMATCH: nx_int = 1 |
| 42 | const NX_FH_FRAME_DIFF: nx_int = 2 |
| 43 | const NX_FH_INVALID: nx_int = 3 |
functions
| 51 | func nx_frame_hash_region(buf: *u8, n: nx_int) -> i64 |
| 65 | func nx_frame_hash_init() -> i64 called by 1: main |
| 73 | func nx_frame_hash_combine(acc: i64, buf: *u8, n: nx_int) -> i64 called by 1: main |
| 88 | func nx_frame_hash_combine_i64(acc: i64, x: i64) -> i64 called by 1: main |
| 107 | func nx_frame_hash_compare( called by 1: main |
| 119 | func main() -> i64 |