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}