nx_avail_map_gate.nx source
↩ module page · 132 lines · 6230 B
1// nx_avail_map_gate.nx -- KAT + negative controls for the shared cross-peer availability map.
2// Native sovereign lane; exit 0 = all pass, N = assertion N failed. Prints every MEASURED value
3// (no self-grading -- the raw counts/picks are the evidence).
4//
5// T1 cross-peer count aggregation is exact
6// T2 rarest-first picks the globally-rarest piece the peer HAS
7// T3 rarest-first advances to the next-rarest once a piece is done
8// T4 NEG-CONTROL: a peer that LACKS the rarest pieces is never told to fetch them
9// T5 a HAVE message bumps a single piece's availability
10// T6 NEG-CONTROL: the lock is load-bearing -- 8 procs x 20 locked increments == exact,
11// the same UNLOCKED loses counts (torn read-modify-write)
12
13import "nx_avail_map.nx"
14import "nx_assert.nx"
15
16// set bit for piece p, MSB-first (bit 7 of byte 0 == piece 0), matching BEP-3 / nx_pw_bitfield_has.
17func gset(bits: *u8, p: i64) -> i64 {
18 let byte: i64 = p / 8
19 let bit: i64 = 7 - (p - byte * 8)
20 bits[byte] = ((bits[byte] as i64) | (1 << bit)) as u8
21 return 0
22}
23
24func main() -> i64 {
25 // ---- T1: cross-peer count aggregation ----
26 // peer A has {0,1,2,3}; B has {1,2,3}; C has {2,3} -> counts = [1,2,3,3,0,0,0,0]
27 let pA: *u8 = sys_mmap(16); gset(pA,0); gset(pA,1); gset(pA,2); gset(pA,3)
28 let pB: *u8 = sys_mmap(16); gset(pB,1); gset(pB,2); gset(pB,3)
29 let pC: *u8 = sys_mmap(16); gset(pC,2); gset(pC,3)
30 let path: *u8 = "/tmp/_nx_avail_t1.bin" as *u8
31 let npc: i64 = 8
32 am_init(path, npc)
33 am_add_bitfield(path, pA, 16, npc)
34 am_add_bitfield(path, pB, 16, npc)
35 am_add_bitfield(path, pC, 16, npc)
36 let cnt: *i64 = sys_mmap(8*16) as *i64
37 am_load(path, cnt, npc)
38 nx_puts_err("T1 count[0]="); nx_puti_err(cnt[0])
39 nx_puts_err("T1 count[1]="); nx_puti_err(cnt[1])
40 nx_puts_err("T1 count[2]="); nx_puti_err(cnt[2])
41 nx_puts_err("T1 count[3]="); nx_puti_err(cnt[3])
42 nx_puts_err("T1 count[4]="); nx_puti_err(cnt[4])
43 if cnt[0] != 1 { return 1 }
44 if cnt[1] != 2 { return 2 }
45 if cnt[2] != 3 { return 3 }
46 if cnt[3] != 3 { return 4 }
47 if cnt[4] != 0 { return 5 }
48
49 let done: *u8 = sys_mmap(64) // all 0 = nothing downloaded yet
50 let av: *i64 = sys_mmap(8*64) as *i64
51 let eff: *i64 = sys_mmap(8*64) as *i64
52
53 // ---- T2: peer A has {0,1,2,3}, nothing done -> rarest = piece 0 (count 1) ----
54 let g2: i64 = am_pick_rarest(path, done, pA, 16, 1, npc, av, eff)
55 nx_puts_err("T2 pick(peer=ABCD, none done)="); nx_puti_err(g2)
56 if g2 != 0 { return 6 }
57
58 // ---- T3: mark piece 0 done -> rarest = piece 1 (count 2) ----
59 done[0] = 1 as u8
60 let g3: i64 = am_pick_rarest(path, done, pA, 16, 1, npc, av, eff)
61 nx_puts_err("T3 pick(piece0 done)="); nx_puti_err(g3)
62 if g3 != 1 { return 7 }
63
64 // ---- T4 NEG-CONTROL: peer C has ONLY {2,3}; nothing done. The globally-rarest pieces are
65 // 0 (1) then 1 (2), but C LACKS both -> it must be told to fetch piece 2 (count 3, the
66 // rarest C actually has), NEVER 0 or 1. Proves the peer-has filter is real. ----
67 done[0] = 0 as u8
68 let g4: i64 = am_pick_rarest(path, done, pC, 16, 1, npc, av, eff)
69 nx_puts_err("T4 pick(peer=only{2,3})="); nx_puti_err(g4)
70 if g4 != 2 { return 8 }
71
72 // ---- T5: a HAVE for piece 4 bumps its count 0->1; a peer with only {4} then picks 4 ----
73 am_add_have(path, 4)
74 let pD: *u8 = sys_mmap(16); gset(pD,4)
75 let g5: i64 = am_pick_rarest(path, done, pD, 16, 1, npc, av, eff)
76 nx_puts_err("T5 pick(after HAVE piece4)="); nx_puti_err(g5)
77 if g5 != 4 { return 9 }
78
79 // ---- T6 NEG-CONTROL: the lock is load-bearing ----
80 // K children x N increments of an ALL-SET bitfield over a fresh map.
81 // LOCKED -> every piece == K*N exactly (no lost RMW).
82 // UNLOCKED -> concurrent read-modify-write tears -> some piece < K*N (lost increments).
83 // K*N kept < 255 so loss shows as a deficit, not hidden behind the saturation ceiling.
84 let K: i64 = 8; let N: i64 = 20; let ncc: i64 = 32; let target: i64 = K * N // 160
85 let allb: *u8 = sys_mmap(16); var bz: i64 = 0; while bz < 4 { allb[bz] = 0xff as u8; bz = bz + 1 } // 32 pieces set
86
87 // -- LOCKED --
88 let lpath: *u8 = "/tmp/_nx_avail_cc_locked.bin" as *u8
89 am_init(lpath, ncc)
90 var k1: i64 = 0
91 while k1 < K {
92 let pid: i64 = sys_fork()
93 if pid == 0 {
94 var j: i64 = 0; while j < N { am_add_bitfield(lpath, allb, 16, ncc); j = j + 1 }
95 sys_exit(0)
96 }
97 k1 = k1 + 1
98 }
99 var r1: i64 = 0; while r1 < K { let st: *i64 = sys_mmap(16) as *i64; sys_wait4(0-1, st, 0); r1 = r1 + 1 }
100 let lc: *i64 = sys_mmap(8*64) as *i64; am_load(lpath, lc, ncc)
101 var lmin: i64 = target + 1; var lmax: i64 = 0; var lp: i64 = 0
102 while lp < ncc { if lc[lp] < lmin { lmin = lc[lp] } if lc[lp] > lmax { lmax = lc[lp] } lp = lp + 1 }
103 nx_puts_err("T6 LOCKED target="); nx_puti_err(target)
104 nx_puts_err("T6 LOCKED min="); nx_puti_err(lmin)
105 nx_puts_err("T6 LOCKED max="); nx_puti_err(lmax)
106 if lmin != target { return 10 }
107 if lmax != target { return 11 }
108
109 // -- UNLOCKED (neg-control) --
110 let upath: *u8 = "/tmp/_nx_avail_cc_unlocked.bin" as *u8
111 am_init(upath, ncc)
112 var k2: i64 = 0
113 while k2 < K {
114 let pid2: i64 = sys_fork()
115 if pid2 == 0 {
116 var j2: i64 = 0; while j2 < N { am_add_bitfield_unlocked(upath, allb, 16, ncc); j2 = j2 + 1 }
117 sys_exit(0)
118 }
119 k2 = k2 + 1
120 }
121 var r2: i64 = 0; while r2 < K { let st2: *i64 = sys_mmap(16) as *i64; sys_wait4(0-1, st2, 0); r2 = r2 + 1 }
122 let uc: *i64 = sys_mmap(8*64) as *i64; am_load(upath, uc, ncc)
123 var umin: i64 = target + 1; var lost: i64 = 0; var up: i64 = 0
124 while up < ncc { if uc[up] < umin { umin = uc[up] } lost = lost + (target - uc[up]); up = up + 1 }
125 nx_puts_err("T6 UNLOCKED target="); nx_puti_err(target)
126 nx_puts_err("T6 UNLOCKED min="); nx_puti_err(umin)
127 nx_puts_err("T6 UNLOCKED total_lost="); nx_puti_err(lost)
128 if lost <= 0 { return 12 } // the neg-control MUST exhibit loss, else the lock proof is vacuous
129
130 nx_puts_err("nx_avail_map_gate verdict=GREEN pass="); nx_puti_err(12)
131 return 0
132}