nx_blob_store.nx
buildroot/runtime/nx_blob_store.nx
about
nx_blob_store.nx -- content-addressed blob store (L0 storage substrate).
ST-1 milestone of NISHI_STORAGE_SUBSTRATE_ROADMAP.md. Foundation
of the 6-layer storage stack; every higher layer (journal, K/V,
schema registry, peer sync, mount adapter) ultimately stores
bytes here keyed by SHA-256.
V1 model:
put_blob(bytes, len) -> 32-byte hash
Compute SHA-256 over the input bytes.
If hash already present, return existing hash (DEDUP).
Otherwise allocate a private copy of the bytes + add an entry.
get_blob(hash, out_buf, max_len) -> actual_len
Linear-scan entries for the matching hash.
If found: assert blob_len <= max_len; copy to out_buf;
return blob_len.
If not found OR oversized: return -1.
has_blob(hash) -> 0/1
V1 scope:
- In-memory store only (file-backed deferred to ST-2)
- Fixed maximum entries (NX_BLOB_STORE_CAPACITY) to keep
allocation deterministic
- Linear-scan index (O(n) per lookup); hash-table queued for ST-2
- Hash representation: 4 i64 fields (32 bytes total, LE-packed)
to avoid u8[32] in struct (NishiLang convention is i64 fields)
Deferred per roadmap:
- File-backed persistence (ST-2)
- Open-addressing hash table for O(1) lookup (ST-2)
- Content-defined chunking for large blobs (ST-2.5)
- Free-list management; current store is APPEND-ONLY (Cardinal
13 -- "tombstoned" blobs would compose via L1 journal entries
marking them is_current=0 rather than actually freeing)
- Concurrent access (multi-thread / multi-process) (ST-4+)
genealogy_id: git_loose_objects_2005 + nix_store_2003 +
ipfs_2015 + cardinal_2026-05-20_storage_substrate
dependencies 2 imports · 17 importers
diagram shows first 10 each side; +0 more imports, +7 more importers in the complete lists below.
imports: nx_syscalls.nxnx_sha256.nx
imported by: nx_blob_store_mcu.nxnx_blob_store_mcu_test.nxnx_blob_store_test.nxnx_emitted_substrate.nxnx_emitted_substrate_test.nxnx_journal_log.nxnx_journal_log_test.nxnx_optimizer_milestone_attest.nxnx_self_build.nxnx_self_build_test.nxnx_spore_up_lifecycle_test.nxnx_spore_up_network_test.nxnx_spore_up_test.nxnx_substrate_manifest.nxnx_substrate_manifest_test.nxnx_win_ledger.nxprobe_blob_journal.nx
structs
| 88 | struct NxBlobHash |
| 98 | struct NxBlobEntry |
| 108 | struct NxBlobStore |
consts
| 69 | const NX_BLOB_STORE_CAPACITY: i64 = 256 // V1 max entries |
| 70 | const NX_BLOB_HASH_BYTES: i64 = 32 // SHA-256 digest |
| 73 | const NX_BLOB_OK: i64 = 0 |
| 74 | const NX_BLOB_BAD_INPUT: i64 = 1 |
| 75 | const NX_BLOB_FULL: i64 = 2 |
| 76 | const NX_BLOB_NOT_FOUND: i64 = 3 |
| 77 | const NX_BLOB_TOO_BIG: i64 = 4 |
| 78 | const NX_BLOB_TAMPER: i64 = 5 |
| 81 | const NX_BLOB_STORE_CANARY_PRE: i64 = 0x4E58424C4F425350 // "NXBLOBSP" |
| 82 | const NX_BLOB_STORE_CANARY_POST: i64 = 0x4E58424C4F424550 // "NXBLOBEP" |
functions
| 119 | func _load_i64_le(buf: *u8, off: i64) -> i64 called by 1: _hash_bytes_to_struct |
| 139 | func _hash_bytes_to_struct(bytes: *u8, len: i64, out: *NxBlobHash) -> i64 |
| 150 | func _entry_hash_eq(e: *NxBlobEntry, h: *NxBlobHash) -> i64 called by 1: _find_entry_idx |
| 159 | func _find_entry_idx(store: *NxBlobStore, h: *NxBlobHash) -> i64 |
| 174 | func _alloc_entry(h: *NxBlobHash, src: *u8, len: i64) -> *NxBlobEntry |
| 193 | func nx_blob_store_new() -> *NxBlobStore |
| 209 | func nx_blob_store_is_valid(s: *NxBlobStore) -> i64 |
| 223 | func nx_blob_store_put( |
| 257 | func nx_blob_store_get( |
| 281 | func nx_blob_store_has(store: *NxBlobStore, hash: *NxBlobHash) -> i64 |
| 290 | func nx_blob_store_count(store: *NxBlobStore) -> i64 |
| 296 | func nx_blob_hash_eq(a: *NxBlobHash, b: *NxBlobHash) -> i64 |
| 307 | func nx_blob_hash_new() -> *NxBlobHash called by 18: mainmainnx_emitted_substrate_add_expected_hash_ofmainnx_journal_log_append+12 calls 1: sys_mmap |