nx_blocklist_store.nx source
↩ module page · 103 lines · 4840 B
1// nx_blocklist_store.nx -- the do-not-recover blocklist on the sovereign seg_store (NOT a TSV). Modeled on
2// nx_app_store. Append-only / immutable: each entry is a record under key "bl:<id>"; status changes
3// (pending -> approved -> retracted) are NEW versions, so the full SUPERVISED history is preserved by construction
4// (additive law) and tamper-evident by content-address. A "__blidx__" index record (newline-separated ids), advanced
5// in the SAME commit, enumerates the whole list atomically. PENDING BY DEFAULT: bl_put writes status=pending and does
6// NOT block; only an operator approve flips it to approved. Record (tab-separated):
7// dhash_hex16 <TAB> threshold <TAB> category <TAB> authority <TAB> date <TAB> ref <TAB> status
8// license_tier: ORIGINAL
9import "nx_seg_store.nx"
10const BL_MAGIC_1048576: i64 = 1048576
11
12const BL_PREFIX: *u8 = "knowledge/blocklist-" as *u8
13
14func bls_cat(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){ dst[off+i]=s[i]; i=i+1 } return off+i }
15func bls_strlen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
16
17func bl_key(kbuf: *u8, id: *u8) -> i64 {
18 var o: i64 = bls_cat(kbuf, 0, "bl:" as *u8)
19 o = bls_cat(kbuf, o, id)
20 kbuf[o] = 0 as u8
21 return o
22}
23
24// is `id` (idlen bytes) already a line in newline-separated buf[0..n)?
25func bl_id_present(buf: *u8, n: i64, id: *u8, idlen: i64) -> i64 {
26 var ls: i64=0; var i: i64=0
27 while i <= n {
28 var eol: i64=0
29 if i==n { eol=1 } else { if buf[i]==10 as u8 { eol=1 } }
30 if eol==1 {
31 if i-ls==idlen { var m: i64=1; var c: i64=0; while c<idlen { if buf[ls+c]!=id[c] { m=0 } c=c+1 } if m==1 { return 1 } }
32 ls=i+1
33 }
34 i=i+1
35 }
36 return 0
37}
38
39// add/update entry <id> with full record bytes (additive NEW version); __blidx__ advanced in the same commit.
40func bl_put_pfx(prefix: *u8, id: *u8, record: *u8, reclen: i64) -> i64 {
41 let kbuf: *u8 = sys_mmap(256)
42 bl_key(kbuf, id)
43 // fresh max+1 segid (ss_next_segid, uncapped) -- the capped ss_manifest count clobbers past the cap
44 let segid: i64 = ss_next_segid(prefix)
45 let w: *i64 = ss_begin()
46 ss_add(w, 1, kbuf, record, reclen)
47 let ipo: *i64 = sys_mmap(16) as *i64
48 let ilo: *i64 = sys_mmap(16) as *i64
49 let idxbuf: *u8 = sys_mmap(BL_MAGIC_1048576)
50 var ilen: i64 = 0
51 if ss_get(prefix, "__blidx__" as *u8, ipo, ilo) >= 0 {
52 let src: *u8 = ipo[0] as *u8
53 var c: i64=0; while c<ilo[0] { idxbuf[ilen]=src[c]; ilen=ilen+1; c=c+1 }
54 }
55 let nl: i64 = bls_strlen(id)
56 if bl_id_present(idxbuf, ilen, id, nl)==0 {
57 var c2: i64=0; while c2<nl { idxbuf[ilen]=id[c2]; ilen=ilen+1; c2=c2+1 }
58 idxbuf[ilen]=10 as u8; ilen=ilen+1
59 }
60 ss_add(w, 1, "__blidx__" as *u8, idxbuf, ilen)
61 return ss_commit(prefix, w, segid)
62}
63
64// current record of <id> -> ptrout[0]/lenout[0]; 1=found, 0=tombstoned, -1=absent
65func bl_get_pfx(prefix: *u8, id: *u8, ptrout: *i64, lenout: *i64) -> i64 {
66 let kbuf: *u8 = sys_mmap(256)
67 bl_key(kbuf, id)
68 return ss_get(prefix, kbuf, ptrout, lenout)
69}
70
71// copy the newline-separated id index into idxbuf; returns its length (0 if empty)
72func bl_index_pfx(prefix: *u8, idxbuf: *u8) -> i64 {
73 let ipo: *i64 = sys_mmap(16) as *i64
74 let ilo: *i64 = sys_mmap(16) as *i64
75 if ss_get(prefix, "__blidx__" as *u8, ipo, ilo) < 0 { return 0 }
76 let src: *u8 = ipo[0] as *u8
77 var i: i64=0; while i<ilo[0] { idxbuf[i]=src[i]; i=i+1 }
78 return ilo[0]
79}
80
81// replace the trailing status field of <id>'s current record with `status` (writes a NEW version, history kept).
82func bl_set_status_pfx(prefix: *u8, id: *u8, status: *u8) -> i64 {
83 let po: *i64 = sys_mmap(16) as *i64
84 let lo: *i64 = sys_mmap(16) as *i64
85 if bl_get_pfx(prefix, id, po, lo) < 1 { return 0 - 1 }
86 let src: *u8 = po[0] as *u8
87 let slen: i64 = lo[0]
88 var lt: i64 = 0 - 1
89 var i: i64 = 0
90 while i < slen { if src[i]==0x09 as u8 { lt=i } i=i+1 }
91 let nbuf: *u8 = sys_mmap(slen + 64)
92 var o: i64 = 0
93 if lt >= 0 { var c: i64=0; while c<=lt { nbuf[o]=src[c]; o=o+1; c=c+1 } } else { var c2: i64=0; while c2<slen { nbuf[o]=src[c2]; o=o+1; c2=c2+1 } nbuf[o]=0x09 as u8; o=o+1 }
94 o = bls_cat(nbuf, o, status)
95 return bl_put_pfx(prefix, id, nbuf, o)
96}
97
98// production-prefix convenience wrappers
99func bl_put(id: *u8, record: *u8, reclen: i64) -> i64 { return bl_put_pfx(BL_PREFIX, id, record, reclen) }
100func bl_get(id: *u8, ptrout: *i64, lenout: *i64) -> i64 { return bl_get_pfx(BL_PREFIX, id, ptrout, lenout) }
101func bl_index(idxbuf: *u8) -> i64 { return bl_index_pfx(BL_PREFIX, idxbuf) }
102func bl_approve(id: *u8) -> i64 { return bl_set_status_pfx(BL_PREFIX, id, "approved" as *u8) }
103func bl_retract(id: *u8) -> i64 { return bl_set_status_pfx(BL_PREFIX, id, "retracted" as *u8) }