PART A — manifest STATE ROOT (the >1-validator prerequisite M0 omitted):
- state.Root() hashes the committed manifest keyspace deterministically via the
zapdb prefix iterator NewIteratorWithStartAndPrefix(nil, prefixManifest),
folding each entry length-prefixed in lexicographic key order. Mirrors
dexvm/state/state.go:395 StateHash, narrowed to the one keyspace.
- VM.computeStateRoot folds blockHash+height with state.Root() (dexvm/vm.go:1260);
ProcessBlock stamps BlockResult.StateRoot (dexvm/vm.go:584).
- The root travels in the block HEADER (new 32B field after parentID; block id
commits to it). Block.Verify recomputes it and REJECTS a mismatch
(errStateRootMismatch) + Aborts staged writes — the safety gate dexvm computed
but never compared.
- Tests: determinism across write order, change-sensitivity (object set / etag /
size / fileIds), Verify-rejects-tampered-root.
PART B — S3 OBJECT path, on-chain-metadata / off-chain-blob split, end to end
(schain/object/):
- Store.PutObject streams the blob to a Volume (OFF chain) -> fid, then commits
only PutManifest{bucket,object,[fid],size,etag} to the VM through a real block
(ON chain). GetObject reads the manifest back and reconstructs from the volume.
- object.Volume is the seam; MemVolume satisfies it for M1 with a fid shape
mirroring hanzo/s3 needle.FileId and etag = base64(md5(blob)) (= ContentMd5).
- M2 PLUG POINT (object/volume.go): swap MemVolume for a github.com/hanzoai/s3
s3/operation.SubmitFiles adapter; nothing in the VM or object.Store changes.
- Test proves blob bytes appear in NO accepted block, the block stays
manifest-small, the manifest IS on chain, and GET byte-reconstructs.
luxfi packages only; zapdb-native; no protobuf in state; SDKROOT needed on macOS.
4.8 KiB
chains
Org: luxfi · Ecosystem: lux · Path: /Users/a/work/lux/luxfi/chains
Origin: https://github.com/luxfi/chains.git
Discovery
This file (CLAUDE.md) is the canonical agent-facing readme; LLM.md is a symlink to it. Update either name and both stay in sync.
Where to look first
README.md— human-facing overview (if present)package.json/Cargo.toml/pyproject.toml/go.mod— language & deps.github/workflows/— CI surfacedocs/— extended docs (if present)
VMs in this repo
Each *vm/ dir is a self-contained block.ChainVM plugin. dexvm is the
reference for VM structure + commit discipline (dual-DB: durable baseDB +
per-block versiondb; one db.CommitBatch() at block Accept).
- schain (
schain/) — the Lux S-Chain storage VM, forked fromdexvm's structure. VMID =ids.ID{'s','c','h','a','i','n'}(dexvm's byte pattern). M0 (DONE): one mutationPutManifest{bucket,object,fileIds,size,etag}round-trips through a real Lux block (BuildBlock→Verify→Accept) and commits the manifest to a real on-disk zapdb in ONE atomic batch at Accept;GetManifestreturns it only after Accept. Commit discipline copied verbatim fromdexvm/vm.go:1194(acceptBlock), minus the cross-chain shared-memory leg a storage VM does not have — accept reduces toCommitBatch()+batch.Write()+db.Abort(). State = typed manifest accessors overversiondb(no protobuf; JSON value bodies, prefix keys), mirroringdexvm/state/state.go. Tx wire = type-byte + JSON, one codec (mirrordexvm/txs/tx.go). No blobs/pinning/ networking yet — that is M1+. Test:schain/schain_test.godrives the genuine VM↔engine contract (SubmitTx→ToEngine PendingTxs→BuildBlock→Verify→Accept) over a REALzapdb.New(t.TempDir(),…); proves staged-not-durable before Accept, durable after, and Reject→Abort discards. M1 (DONE): TWO parts. PART A — manifest STATE ROOT (the multi-validator safety prerequisite M0 omitted):state.Root()hashes the committed manifest keyspace deterministically via the zapdb prefix iteratorNewIteratorWithStartAndPrefix(nil, prefixManifest), folding each entry length-prefixed (len(k)||k||len(v)||v) in lexicographic key order (mirror ofdexvm/state/state.go:395StateHash, narrowed to the one keyspace; last-block pointer excluded — it is consensus binding folded via blockHash/height, not object state).VM.computeStateRootfolds blockHash+height withstate.Root()(mirrordexvm/vm.go:1260);ProcessBlockstamps it intoBlockResult.StateRoot(mirrordexvm/vm.go:584). The root travels in the block HEADER (new 32-byte field after parentID; block id commits to it) andBlock.Verifyrecomputes it and REJECTS a mismatch (errStateRootMismatch) + Aborts staged writes — this is the >1-validator safety gate dexvm computed but never compared. Tests (schain/stateroot_test.go): determinism across write order, change-sensitivity (object set / etag / size / fileIds each move the root), and Verify-rejects-tampered-root. PART B — S3 OBJECT path, on-chain-metadata / off-chain-blob split proven end to end (schain/object/):Store.PutObjectstreams the blob to aVolume(OFF chain) → fid, then commits onlyPutManifest{bucket,object,[fid],size,etag}to the VM through a real block (ON chain);GetObjectreads the manifest back and reconstructs the blob from the volume.object.Volumeis the SEAM (Write(blob)→fid, Read(fid)→blob); M1 satisfies it with a faithful in-memoryMemVolumewhose fid shape mirrors hanzo/s3'sneedle.FileId(volumeId,needleIdCookie) and whose etag isbase64(md5(blob))(= hanzo/s3ContentMd5). M2 PLUG POINT (marked inobject/volume.go): swapMemVolumefor a thin adapter overgithub.com/ hanzoai/s3s3/operation.SubmitFiles(assign volume + stream needle →.Fid) and a needle GET — nothing in the VM orobject.Storechanges. Kept inside chains/schain (not importing the hanzoai/s3 module into luxfi/chains) to respect the org/module boundary while proving the exact data model. Test (schain/object_roundtrip_test.go): asserts the blob bytes appear in NO accepted block (bytes.Containsoverblk.Bytes()) and the block stays manifest-small (<4KiB for a 68KiB blob), the manifest IS on chain, and GET byte-reconstructs.
Test/build env gotcha (macOS)
The whole chains test suite links CGO deps that need -lresolv; the CLT cc
fails with library 'resolv' not found unless the macOS SDK syslibroot is set.
Run tests with SDKROOT="$(xcrun --show-sdk-path)" go test ./schain/.... This
affects dexvm and every other VM here too — it is NOT schain-specific.
Sibling repos
See the org-level LLM.md at /Users/a/work/lux/luxfi/LLM.md for the full inventory of sibling repos and inter-repo dependencies.