code wiki / (root) / nx_log_chunked_test.nx

nx_log_chunked_test.nx source

↩ module page · 99 lines · 4589 B

1// nx_log_chunked_test.nx -- append-only Merkle-linked log shape. 2 3import "nx_syscalls.nx" 4import "nx_tier.nx" 5import "nx_sha256.nx" 6import "nx_cbor.nx" 7import "nx_log_chunked.nx" 8 9func main() -> nx_int { 10 // Small chunk + small manifest cap to force flush after a few spans. 11 let log: *ChunkedLog = nx_lc_alloc(512, 16) 12 if log.chunk_pos != 0 { return 1 } 13 if log.n_chunks != 0 { return 2 } 14 if log.last_hash_off != 0 - 1 { return 3 } 15 16 let attrs: *i64 = (sys_mmap(32)) as *i64 17 attrs[0] = 0xAA; attrs[1] = 100 18 attrs[2] = 0xBB; attrs[3] = 200 19 20 // ===== Append a few spans (no chunk overflow yet) ============= 21 nx_lc_append_span(log, 1000, 1, 0 - 1, 0, 0, 100, attrs, 2, 1700000000) 22 nx_lc_append_span(log, 1000, 2, 1, 1, 100, 105, attrs, 2, 1700000001) 23 nx_lc_append_span(log, 1000, 3, 1, 2, 105, 110, attrs, 2, 1700000002) 24 25 if log.chunk_n_spans != 3 { return 10 } 26 if log.chunk_first_tid != 1000 { return 11 } 27 if log.chunk_last_tid != 1000 { return 12 } 28 if log.n_chunks != 0 { return 13 } // not flushed yet 29 30 // ===== Explicit flush ========================================= 31 let rc1: nx_int = nx_lc_flush(log, 1700000003) 32 if rc1 != 0 { return 20 } 33 if log.n_chunks != 1 { return 21 } 34 if log.chunk_pos != 0 { return 22 } 35 if log.chunk_n_spans != 0 { return 23 } 36 37 // Manifest record sanity 38 if nx_lc_rec_get(log, 0, NX_LC_REC_F_INDEX) != 0 { return 24 } 39 if nx_lc_rec_get(log, 0, NX_LC_REC_F_N_SPANS) != 3 { return 25 } 40 if nx_lc_rec_get(log, 0, NX_LC_REC_F_WRITTEN_AT) != 1700000003 { return 26 } 41 if nx_lc_rec_get(log, 0, NX_LC_REC_F_PARENT_HASH_OFF) != 0 - 1 { return 27 } 42 if nx_lc_rec_get(log, 0, NX_LC_REC_F_FIRST_TRACE) != 1000 { return 28 } 43 if nx_lc_rec_get(log, 0, NX_LC_REC_F_LAST_TRACE) != 1000 { return 29 } 44 45 // ===== Second chunk: should chain parent_hash to chunk 0 ===== 46 nx_lc_append_span(log, 2000, 4, 0 - 1, 0, 200, 210, attrs, 2, 1700000004) 47 nx_lc_append_span(log, 2001, 5, 4, 7, 210, 220, attrs, 2, 1700000005) 48 nx_lc_flush(log, 1700000006) 49 if log.n_chunks != 2 { return 30 } 50 51 // Parent-hash-off of chunk 1 must equal hash-off of chunk 0 52 let chunk0_hash_off: nx_int = nx_lc_rec_get(log, 0, NX_LC_REC_F_HASH_OFF) 53 let chunk1_parent_off: nx_int = nx_lc_rec_get(log, 1, NX_LC_REC_F_PARENT_HASH_OFF) 54 if chunk0_hash_off != chunk1_parent_off { return 31 } 55 56 // Last_trace bumped to 2001 in chunk 1 57 if nx_lc_rec_get(log, 1, NX_LC_REC_F_LAST_TRACE) != 2001 { return 32 } 58 59 // ===== Chain integrity verifier =============================== 60 if nx_lc_verify_chain(log) != NX_LC_VERIFY_VALID { return 40 } 61 62 // Tamper with the chain: corrupt chunk 1's parent_hash_off, then 63 // verify catches it. 64 log.manifest[1 * NX_LC_REC_FIELDS + NX_LC_REC_F_PARENT_HASH_OFF] = 0xDEAD 65 if nx_lc_verify_chain(log) != NX_LC_VERIFY_PARENT_BROKEN { return 41 } 66 // Repair (set back to the correct value) 67 log.manifest[1 * NX_LC_REC_FIELDS + NX_LC_REC_F_PARENT_HASH_OFF] = chunk0_hash_off 68 if nx_lc_verify_chain(log) != NX_LC_VERIFY_VALID { return 42 } 69 70 // Tamper with the index: set chunk 1's index to 5 -> ORDER_REVERSED 71 log.manifest[1 * NX_LC_REC_FIELDS + NX_LC_REC_F_INDEX] = 5 72 if nx_lc_verify_chain(log) != NX_LC_VERIFY_ORDER_REVERSED { return 43 } 73 log.manifest[1 * NX_LC_REC_FIELDS + NX_LC_REC_F_INDEX] = 1 // repair 74 75 // ===== Auto-flush via overflow ================================= 76 // 77 // Fill the chunk to within 128 bytes of capacity to trigger the 78 // overflow-flush path on the next append. 79 log.chunk_pos = log.chunk_cap - 100 // < 128 free 80 log.chunk_n_spans = 1 81 log.chunk_first_tid = 3000 82 log.chunk_last_tid = 3000 83 nx_lc_append_span(log, 3000, 99, 0 - 1, 0, 0, 1, attrs, 2, 1700000010) 84 // Should have flushed -> n_chunks=3 85 if log.n_chunks != 3 { return 50 } 86 87 // ===== Verify the chain still valid after overflow flush ===== 88 if nx_lc_verify_chain(log) != NX_LC_VERIFY_VALID { return 51 } 89 90 // ===== Verdict-band coverage ================================= 91 if nx_lc_verify_verdict_is_valid(NX_LC_VERIFY_VALID) != 1 { return 60 } 92 if nx_lc_verify_verdict_is_valid(NX_LC_VERIFY_HASH_MISMATCH) != 1 { return 61 } 93 if nx_lc_verify_verdict_is_valid(NX_LC_VERIFY_PARENT_BROKEN) != 1 { return 62 } 94 if nx_lc_verify_verdict_is_valid(NX_LC_VERIFY_ORDER_REVERSED) != 1 { return 63 } 95 if nx_lc_verify_verdict_is_valid(0 - 1) != 0 { return 64 } 96 if nx_lc_verify_verdict_is_valid(NX_LC_VERIFY_N_VERDICTS) != 0 { return 65 } 97 98 return 0 99}