code wiki / (root) / nx_substrate_manifest_test.nx

nx_substrate_manifest_test.nx source

↩ module page · 138 lines · 6319 B

1// nx_substrate_manifest_test.nx -- smoke for nx_substrate_manifest 2// EM-3 partial. 3// 4// Exercises: 5// 1. Allocation + canary + initial state 6// 2. Add expected hashes; n_expected increments 7// 3. Idempotent re-add 8// 4. is_complete + n_missing reflect state correctly 9// 5. INGEST happy path: bytes hash to claimed AND claimed is in manifest -> stored, received_flag set, n_received++ 10// 6. NOT_IN_MANIFEST: ingest with claimed-hash NOT in expected set -> rejected; counter incremented 11// 7. HASH_MISMATCH: ingest with bytes that DON'T hash to claimed -> rejected; tamper counter 12// 8. ALREADY_RECEIVED: re-ingest same blob -> idempotent 13// 9. Multiple distinct ingests -> n_received tracks correctly; eventually is_complete 14// 10. Bad-input gates + canary tamper 15 16import "nx_syscalls.nx" 17import "nx_blob_store.nx" 18import "nx_substrate_manifest.nx" 19 20func _fill_pattern(buf: *u8, len: i64, seed: i64) -> i64 { 21 var i: i64 = 0 22 while i < len { 23 buf[i] = (((i * 13) + seed) & 255) as u8 24 i = i + 1 25 } 26 return 0 27} 28 29// Compute SHA-256-derived NxBlobHash by passing bytes through a 30// throwaway store (the store dedups internally; we use the hash 31// it returns). 32func _compute_hash(bytes: *u8, len: i64) -> *NxBlobHash { 33 let throwaway: *NxBlobStore = nx_blob_store_new() 34 let h: *NxBlobHash = nx_blob_hash_new() 35 nx_blob_store_put(throwaway, bytes, len, h) 36 return h 37} 38 39func main() -> i64 { 40 let store: *NxBlobStore = nx_blob_store_new() 41 let m: *NxSubstrateManifest = nx_substrate_manifest_new(store) 42 43 // ----- 1. Initial state ----- 44 if nx_substrate_manifest_is_valid(m) != 1 { return 1 } 45 if nx_substrate_manifest_is_complete(m) != 0 { return 2 } // empty is not complete 46 if nx_substrate_manifest_n_missing(m) != 0 { return 3 } 47 if nx_substrate_manifest_n_rejected_unknown(m) != 0 { return 4 } 48 if nx_substrate_manifest_n_rejected_tamper(m) != 0 { return 5 } 49 50 // ----- 2. Build 3 expected blobs ----- 51 let p1: *u8 = sys_mmap(64) 52 _fill_pattern(p1, 32, 10) 53 let h1: *NxBlobHash = _compute_hash(p1, 32) 54 55 let p2: *u8 = sys_mmap(64) 56 _fill_pattern(p2, 32, 20) 57 let h2: *NxBlobHash = _compute_hash(p2, 32) 58 59 let p3: *u8 = sys_mmap(64) 60 _fill_pattern(p3, 32, 30) 61 let h3: *NxBlobHash = _compute_hash(p3, 32) 62 63 // ----- 3. Add expected hashes ----- 64 if nx_substrate_manifest_add_expected(m, h1) != NX_SM_INGESTED { return 6 } 65 if nx_substrate_manifest_add_expected(m, h2) != NX_SM_INGESTED { return 7 } 66 if nx_substrate_manifest_add_expected(m, h3) != NX_SM_INGESTED { return 8 } 67 if m.n_expected != 3 { return 9 } 68 if nx_substrate_manifest_n_missing(m) != 3 { return 10 } 69 if nx_substrate_manifest_is_complete(m) != 0 { return 11 } 70 71 // ----- 4. Idempotent re-add of an existing expected hash ----- 72 if nx_substrate_manifest_add_expected(m, h1) != NX_SM_ALREADY_RECEIVED { return 12 } 73 if m.n_expected != 3 { return 13 } // count unchanged 74 75 // ----- 5. Ingest happy path: blob 1 ----- 76 if nx_substrate_manifest_ingest(m, h1, p1, 32) != NX_SM_INGESTED { return 14 } 77 if m.n_received != 1 { return 15 } 78 if nx_substrate_manifest_n_missing(m) != 2 { return 16 } 79 if nx_substrate_manifest_is_complete(m) != 0 { return 17 } 80 81 // ----- 6. NOT_IN_MANIFEST: ingest a hash not in the expected set ----- 82 let p_extra: *u8 = sys_mmap(64) 83 _fill_pattern(p_extra, 32, 999) 84 let h_extra: *NxBlobHash = _compute_hash(p_extra, 32) 85 if nx_substrate_manifest_ingest(m, h_extra, p_extra, 32) != NX_SM_NOT_IN_MANIFEST { return 18 } 86 if nx_substrate_manifest_n_rejected_unknown(m) != 1 { return 19 } 87 if m.n_received != 1 { return 20 } // unchanged 88 89 // ----- 7. HASH_MISMATCH: bytes don't hash to claimed ----- 90 // Claim h2 but pass p3's bytes. Verifier hashes p3 -> h3 != h2 -> reject. 91 if nx_substrate_manifest_ingest(m, h2, p3, 32) != NX_SM_HASH_MISMATCH { return 21 } 92 if nx_substrate_manifest_n_rejected_tamper(m) != 1 { return 22 } 93 // The actual blob (h3 of p3) is now in the blob store via put_blob 94 // dedup; that's fine. But the manifest slot for h2 is STILL not 95 // marked received. 96 if m.n_received != 1 { return 23 } 97 if m.received_flags[1] != 0 { return 24 } // h2's slot still 0 98 99 // ----- 8. ALREADY_RECEIVED: re-ingest blob 1 ----- 100 if nx_substrate_manifest_ingest(m, h1, p1, 32) != NX_SM_ALREADY_RECEIVED { return 25 } 101 if m.n_received != 1 { return 26 } // count unchanged 102 103 // ----- 9. Complete the manifest ----- 104 if nx_substrate_manifest_ingest(m, h2, p2, 32) != NX_SM_INGESTED { return 27 } 105 if m.n_received != 2 { return 28 } 106 if nx_substrate_manifest_ingest(m, h3, p3, 32) != NX_SM_INGESTED { return 29 } 107 if m.n_received != 3 { return 30 } 108 if nx_substrate_manifest_is_complete(m) != 1 { return 31 } 109 if nx_substrate_manifest_n_missing(m) != 0 { return 32 } 110 111 // Verify each blob is queryable from the underlying L0 store. 112 if nx_blob_store_has(store, h1) != 1 { return 33 } 113 if nx_blob_store_has(store, h2) != 1 { return 34 } 114 if nx_blob_store_has(store, h3) != 1 { return 35 } 115 116 // ----- 10. Bad-input gates + canary tamper ----- 117 let null_hash: *NxBlobHash = (0 as i64) as *NxBlobHash 118 let null_bytes: *u8 = (0 as i64) as *u8 119 if nx_substrate_manifest_add_expected(m, null_hash) != NX_SM_BAD_INPUT { return 36 } 120 if nx_substrate_manifest_ingest(m, null_hash, p1, 32) != NX_SM_BAD_INPUT { return 37 } 121 if nx_substrate_manifest_ingest(m, h1, null_bytes, 32) != NX_SM_BAD_INPUT { return 38 } 122 if nx_substrate_manifest_ingest(m, h1, p1, -1) != NX_SM_BAD_INPUT { return 39 } 123 124 // Canary tamper -> all ops refuse. 125 m.canary_post = 0xDEADBEEF 126 if nx_substrate_manifest_is_valid(m) != 0 { return 40 } 127 if nx_substrate_manifest_add_expected(m, h1) != NX_SM_TAMPER { return 41 } 128 if nx_substrate_manifest_ingest(m, h1, p1, 32) != NX_SM_TAMPER { return 42 } 129 if nx_substrate_manifest_is_complete(m) != 0 { return 43 } 130 if nx_substrate_manifest_n_missing(m) != -1 { return 44 } 131 132 // ----- 11. Sealed-enum gate ----- 133 if nx_sm_verdict_is_valid(NX_SM_INGESTED) != 1 { return 45 } 134 if nx_sm_verdict_is_valid(-1) != 0 { return 46 } 135 if nx_sm_verdict_is_valid(NX_SM_N_VERDICTS) != 0 { return 47 } 136 137 return 0 138}