code wiki / (root) / nx_swarm_sim.nx

nx_swarm_sim.nx source

↩ module page · 147 lines · 6714 B

1// nx_swarm_sim.nx -- deterministic swarm simulator + download engine (bits-up, replayable). 2// 3// module: nishi-core.torrent.swarm_sim 4// depends: nx_stream_picker.nx (-> nx_piece_manager), nx_syscalls.nx 5// capability: CORE_COMPUTE 6// wired_status: FULLY_WIRED 7// 8// The "session loop" made TESTABLE: a discrete-round model that drives the REAL picker 9// (nx_sp_stream_pick / nx_pm_rarest) and the REAL endgame logic (nx_sp_in_endgame) against 10// a scripted swarm of honest / stalling / lying peers. Because every decision is integer and 11// the peer script is fixed, the whole download REPLAYS bit-for-bit -- the determinism exceed 12// no mainstream client has, here turned into a measurement instrument: a decision-trace hash 13// that must be identical across runs. This is also the substrate the benchmark grades on 14// (adverse-swarm completion, endgame value, streaming-to-playable). It is a SIMULATOR, not a 15// live client -- it measures the selection brain, honestly named as such; the live socket loop 16// is the named next rung. 17 18import "nx_stream_picker.nx" 19const NX_MAGIC_1000000007: i64 = 1000000007 20 21const NX_SS_HONEST: i64 = 0 // delivers a requested piece it holds (verify passes) 22const NX_SS_STALL: i64 = 1 // advertises pieces but never delivers (snub) 23const NX_SS_LIE: i64 = 2 // advertises pieces it will not deliver / delivers corrupt (verify fails) 24 25const NX_SS_DNF: i64 = 0 - 1 // did-not-finish within max_rounds (a real stall, reported honestly) 26 27// availability[piece] = number of connected peers ADVERTISING it (liars advertise -- that is the lie, 28// and it is exactly why availability alone cannot be trusted; honesty is proven only on delivery). 29func nx_ss_availability(peer_has: *i64, npeers: i64, n: i64, out_avail: *i64) -> i64 { 30 var j: i64 = 0 31 while j < n { out_avail[j] = 0; j = j + 1 } 32 var p: i64 = 0 33 while p < npeers { 34 j = 0 35 while j < n { 36 if peer_has[p * n + j] == 1 { out_avail[j] = out_avail[j] + 1 } 37 j = j + 1 38 } 39 p = p + 1 40 } 41 return 0 42} 43 44// lowest-index peer ADVERTISING `piece` (who a single-peer request would target); -1 if none. 45func nx_ss_holder(peer_has: *i64, npeers: i64, n: i64, piece: i64) -> i64 { 46 var p: i64 = 0 47 while p < npeers { 48 if peer_has[p * n + piece] == 1 { return p } 49 p = p + 1 50 } 51 return 0 - 1 52} 53 54// is there an HONEST peer that actually holds `piece`? (an endgame broadcast succeeds iff yes) 55func nx_ss_any_honest_holder(peer_has: *i64, behavior: *i64, npeers: i64, n: i64, piece: i64) -> i64 { 56 var p: i64 = 0 57 while p < npeers { 58 if peer_has[p * n + piece] == 1 { 59 if behavior[p] == NX_SS_HONEST { return 1 } 60 } 61 p = p + 1 62 } 63 return 0 64} 65 66// count pieces we still need. 67func nx_ss_outstanding(have: *i64, n: i64) -> i64 { 68 var c: i64 = 0 69 var j: i64 = 0 70 while j < n { if have[j] == 0 { c = c + 1 } j = j + 1 } 71 return c 72} 73 74// Run a deterministic download to completion (or DNF). `have[]` is mutated to all-1 on success. 75// streaming==1 -> nx_sp_stream_pick(playhead = lowest-needed, window); else nx_pm_rarest. 76// endgame==1 -> once outstanding<=threshold, request the target from ALL peers (delivered iff 77// any HONEST peer holds it); otherwise from the lowest-index holder (delivered iff 78// THAT peer is honest -- so a low-index snub on a needed piece stalls naive mode, 79// the adverse failure endgame's broadcast repairs). 80// Writes a decision-trace hash to *out_trace (same scenario+flags => same hash => replay-proof). 81// Returns rounds-to-complete, or NX_SS_DNF if unfinished within max_rounds. 82func nx_ss_run(peer_has: *i64, behavior: *i64, npeers: i64, n: i64, have: *i64, 83 streaming: i64, window: i64, endgame: i64, threshold: i64, 84 max_rounds: i64, out_trace: *i64) -> i64 { 85 let avail: *i64 = sys_mmap(n * 8) as *i64 86 nx_ss_availability(peer_has, npeers, n, avail) 87 var trace: i64 = 0 88 var rounds: i64 = 0 89 while rounds <= max_rounds { 90 let outstanding: i64 = nx_ss_outstanding(have, n) 91 if outstanding == 0 { out_trace[0] = trace; return rounds } 92 93 var target: i64 = 0 - 1 94 if streaming == 1 { 95 let playhead: i64 = nx_sp_sequential(have, n) 96 target = nx_sp_stream_pick(avail, have, n, playhead, window) 97 } else { 98 target = nx_pm_rarest(avail, have, n) 99 } 100 if target < 0 { out_trace[0] = trace; return NX_SS_DNF } // nothing pickable (no available source) 101 102 var use_eg: i64 = 0 103 if endgame == 1 { if nx_sp_in_endgame(outstanding, threshold) == 1 { use_eg = 1 } } 104 var delivered: i64 = 0 105 if use_eg == 1 { 106 delivered = nx_ss_any_honest_holder(peer_has, behavior, npeers, n, target) 107 } else { 108 let p: i64 = nx_ss_holder(peer_has, npeers, n, target) 109 if p >= 0 { if behavior[p] == NX_SS_HONEST { delivered = 1 } } 110 } 111 if delivered == 1 { have[target] = 1 } 112 113 trace = (trace * 31 + target * 2 + delivered) % NX_MAGIC_1000000007 // bounded deterministic fold 114 rounds = rounds + 1 115 } 116 out_trace[0] = trace 117 return NX_SS_DNF 118} 119 120// Streaming "watch while you download" metric: the round at which IN-ORDER playback can begin, 121// i.e. the first round where we hold `lookahead` contiguous pieces from index 0. Lower is better. 122// With streaming==1 the picker fills from the playhead so this comes early; with rarest-first 123// (streaming==0) on a skewed-availability swarm the low indices arrive late -> playable later. 124// Returns the round number, or NX_SS_DNF if never reached within max_rounds. 125func nx_ss_rounds_to_playable(peer_has: *i64, behavior: *i64, npeers: i64, n: i64, have: *i64, 126 streaming: i64, window: i64, lookahead: i64, max_rounds: i64) -> i64 { 127 let avail: *i64 = sys_mmap(n * 8) as *i64 128 nx_ss_availability(peer_has, npeers, n, avail) 129 var rounds: i64 = 0 130 while rounds <= max_rounds { 131 if nx_sp_can_play(have, n, 0, lookahead) == 1 { return rounds } 132 if nx_ss_outstanding(have, n) == 0 { return rounds } 133 134 var target: i64 = 0 - 1 135 if streaming == 1 { 136 let playhead: i64 = nx_sp_sequential(have, n) 137 target = nx_sp_stream_pick(avail, have, n, playhead, window) 138 } else { 139 target = nx_pm_rarest(avail, have, n) 140 } 141 if target < 0 { return NX_SS_DNF } 142 let p: i64 = nx_ss_holder(peer_has, npeers, n, target) 143 if p >= 0 { if behavior[p] == NX_SS_HONEST { have[target] = 1 } } 144 rounds = rounds + 1 145 } 146 return NX_SS_DNF 147}