4 Commits
Author SHA1 Message Date
zeekayandHanzo Dev cf6e2972c0 schain: migrate tx wire json→native ZAP (last codec on S-Chain)
PutManifestTx + AllocateTx now encode as [typeByte][ZAP object] instead of
[typeByte][json body]. Fixed-offset ZAP objects (FileIDs/pubkey/sig as
variable tails, NodeID/Fingerprint as fixed bytes) — deterministic by
construction, TxID = Checksum256(wire). Parser dispatches on data[0], rejects
trailing bytes (canonical). Removed the unused generic json Marshal[T].
11 txs tests green (round-trip all fields incl ML-DSA pubkey/sig, determinism,
trailing-byte + bad-type rejection); schain/pinning/state suites green.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-14 15:32:59 -07:00
zeekay 6552bd69cd schain: Stage 2 — cryptographically verifiable signed pinned-writer (deletes raft's serialized writer)
The Stage-1 allocate gate was owner-gated in LOGIC (pinning.IsOwner over the
block's threaded proposer) but UNENFORCEABLE by a verifying node: a Lux block
carries no verifiable proposer, and resolving one (GetValidatorSet) can be a
network call, so the gate could not run inside the pure, local block apply. The
chain was therefore unsafe for >1 validator.

Make ownership self-attested and cryptographically verifiable:

- AllocateTx gains Signer/SignerScheme/SignerPubKey/Sig + Epoch/Nonce/Fingerprint.
  Sig is an ML-DSA signature (FIPS 204, the SAME scheme the validator NodeID
  derives from) over the SP 800-185-framed bytes Range|Count|Epoch|Nonce|
  Fingerprint. The owning proposer signs at BuildBlock with its staking key.

- Verify (applyAllocate) is pure + local: recompute owner = pinning.Owner(R,
  V@epoch); require Signer == owner; re-derive the NodeID from the carried public
  key (ids.DeriveMLDSA — the NodeID is a SHAKE256-384 commitment to the key) and
  require it to equal Signer; ML-DSA-verify the signature. Any failure rejects the
  whole block (fail closed).

- Validator-set locality: GetValidatorOutput carries no ML-DSA key, so Verify
  binds the key via the NodeID commitment instead of a set lookup, and uses the
  EpochFingerprint carried in the tx (recomputed from the local snapshot) as the
  DESIGN 6.4 guard — the network call (set resolution) happens in BuildBlock,
  never in Verify.

A non-owner's forged allocate is unverifiable by construction: it cannot sign as
the owner (no key), and claiming the owner's NodeID with a foreign key fails the
re-derivation. This is the property that replaces raft's serialized writer.

Tests (real ML-DSA keys, production NodeID derivation, no bypass): owner-signed
accepted + contiguous/monotonic; non-owner-with-VALID-key rejected; forged sig
rejected; foreign-key-for-owner-NodeID rejected; tampered tx rejected; epoch and
fingerprint mismatch rejected; verifier accepts owner-signed block regardless of
relay; state-root/manifest tests stay green. Full schain suite green under -race.
2026-06-25 15:47:37 -07:00
zeekay 64163f8e02 schain: Stage 1 — leaderless pinned-writer allocator (AllocateTx + owner gate)
Replaces raft's serialization role for volume/fileId allocation with
owner-gated VM state riding native Lux consensus. The HRW owner of a range
is the only emitter of allocate mutations, enforced at block Verify — no
leader election.

- txs: AllocateTx{Range,Count} mirrors PutManifestTx codec (type byte + JSON);
  Verify rejects empty range / zero count. Owner gate is block-level, not in
  the tx (a tx cannot see the block's validator set).
- state: per-range counter alloc/<range> (GetAlloc/SetAlloc), folded into the
  SHAKE256 state Root() alongside manifests via rootPrefixes; domain bumped to
  SCHAIN_STATE_ROOT_V2 so the root covers allocator divergence.
- vm: applyAllocate increments alloc/<range> by Count, reserving [base,base+Count)
  — pure function of committed state, deterministic, version-layer only, no I/O.
  Owner gate: pinning.IsOwner(range, proposer, members) in ProcessBlock; a
  non-owner (or no-validator-set) allocate fails the whole block. ProcessBlock
  now Aborts staged state first so read-modify-write applies over COMMITTED
  state (idempotent across BuildBlock+Verify re-application).
- BlockContext{Members,Proposer,Epoch} threads the validator set + proposer as
  explicit deterministic inputs (no network I/O in Verify). BlockContextBuilder
  is the seam to the real consensus runtime (master-cutover stage); empty
  context = M0/no-allocate path, AllocateTx fails closed.

Tests (green, no go.sum bypass):
- owner allocates: contiguous + monotonic across blocks ([0,8) then [8,13)).
- non-owner rejected: proposer-side (BuildBlock) and verifier-side (Verify) →
  errNonOwnerAllocate; counter untouched; nothing leaks to durable base.
- empty validator set: fails closed (errNoValidatorSet).
- parallel distinct ranges: independent owners allocate independently.
- same range: serializes through its one owner.
- state root covers alloc: counter change moves Root(); Verify rejects a
  tampered claimed root (errStateRootMismatch).
2026-06-25 15:15:37 -07:00
zeekay 0a20786095 schain: M0 storage-chain VM skeleton (manifest → zapdb through a real block)
Fork dexvm's commit discipline into a new storage VM (VMID 'schain'): dual-DB
(durable zapdb base + per-block versiondb), pure-deterministic ProcessBlock, ONE
CommitBatch at Accept (mirrors dexvm/vm.go:1194, block.go:159). M0 op: PutManifest
{bucket,object,fileIds,size,etag} staged in the version layer, durable only after
Accept; GetManifest reads committed state. Proves the on-chain-metadata / off-chain-
blob architecture for an embedded decentralized S3 'S-chain'.

schain_test.go (real on-disk zapdb.New): manifest absent in base DB before Accept,
present after — versiondb→CommitBatch proven end-to-end; +Reject-aborts-staged and
tx-codec round-trip. go vet + -race clean.

M1 notes (in-code): add a manifest STATE ROOT before multi-validator consensus
(dexvm computeStateRoot pattern); keep any future cross-chain blob-ref leg separate
from the manifest commit; add genesis/config. Next: wire the S3 Sig-V4 gateway
(PUT→needle off-chain + PutManifest on-chain; GET→manifest+needle stream).
2026-06-25 12:44:03 -07:00