Skip to content

feat(storagechallenge): add LEP-6 deterministic primitives#287

Merged
j-rafique merged 1 commit into
supernode/LEP-6-chain-client-extensionsfrom
supernode/LEP-6-deterministic-primitives
May 4, 2026
Merged

feat(storagechallenge): add LEP-6 deterministic primitives#287
j-rafique merged 1 commit into
supernode/LEP-6-chain-client-extensionsfrom
supernode/LEP-6-deterministic-primitives

Conversation

@j-rafique
Copy link
Copy Markdown
Contributor

Introduces pkg/storagechallenge/deterministic/lep6.go, the off-chain computation library shared by the storage_challenge runtime, recheck service, and self-healing dispatcher. Every function is pure (no I/O, no clock, no goroutines) so independent reporters challenging the same (target, ticket) pair produce byte-identical StorageProofResult fields.

Functions land in two categories:

CHAIN-MIRRORED (must match lumera/x/audit/v1/keeper/audit_peer_assignment.go byte-for-byte; the chain re-runs them to validate MsgSubmitEpochReport):

  • SelectLEP6Targets — 1/3 deterministic target subset (SHA-256(seed||0x00||account||0x00||"challenge_target"), targetCount = ceil(N/divisor) clamped to [1, N])
  • PairChallengerToTarget / AssignChallengerTargets — challenger->target pairing (label "pair"), with no-self and lex tie-break

SUPERNODE-CANONICAL (chain stores outputs as opaque strings; this file defines the canonical encoding all reporters must use to stay in lockstep):

  • ClassifyTicketBucket — RECENT/OLD bucket classification using Action.BlockHeight (Action.UpdatedHeight does not exist; see docs/plans/LEP6_SUPERNODE_IMPLEMENTATION_PLAN.md "Resolved Decision 3")
  • SelectTicketForBucket — deterministic per-(target,bucket) ticket pick with excluded-set support for active heal ops
  • SelectArtifactClass — LEP-6 §10 weighted roll (20% INDEX / 80% SYMBOL) with deterministic fallback when a class has no artifacts
  • SelectArtifactOrdinal — uniform ordinal mod artifactCount
  • ComputeMultiRangeOffsets — k=4 range offsets in [0, size-rangeLen)
  • ComputeCompoundChallengeHash — BLAKE3 over concat of slices in offset order (lukechampine.com/blake3 to match the chain's library)
  • DerivationInputHash — canonical hex of derivation inputs
  • TranscriptHash — full canonical transcript identifier with sorted observer ids; struct-input form prevents field-order mistakes

Domain separators ("challenge_target", "pair", "ticket_rank", "artifact_class", "artifact_ordinal", "range_offset", "derivation_input", "transcript") and enum string forms ("INDEX"/ "SYMBOL", "RECENT"/"OLD"/"PROBATION"/"RECHECK") are package constants; freezing them prevents accidental drift between callers and tests. Any change is a protocol-level break that requires versioning.

Tests:

  • TestStorageTruthAssignmentHash_KnownVector locks the byte-level SHA-256 composition against an independent computation, guaranteeing the chain-mirrored helper has not drifted.
  • TestSelectLEP6Targets_OneThirdCoverage_AssignmentMatchesChain uses the chain's own audit_peer_assignment_test.go fixture (seed="01234567890123456789012345678901", active={sn-a..sn-f}, divisor=3) — output {sn-f, sn-e}.
  • TestAssignChallengerTargets_KnownAssignment locks the full pairing {sn-a -> sn-f, sn-b -> sn-e}.
  • TestSelectArtifactClass_WeightedDistribution validates ~20% INDEX over 5000 draws (±2% tolerance).
  • Determinism, sensitivity, error-path, and out-of-bounds tests for every primitive.

Verified: go test ./pkg/storagechallenge/deterministic/... passes; the existing deterministic_test.go pre-LEP-6 tests continue to pass.

@j-rafique j-rafique self-assigned this Apr 30, 2026
@j-rafique j-rafique force-pushed the supernode/LEP-6-chain-client-extensions branch from fba3844 to 6d3160b Compare May 4, 2026 11:39
@j-rafique j-rafique force-pushed the supernode/LEP-6-deterministic-primitives branch from 941967b to 0dc9475 Compare May 4, 2026 11:50
@j-rafique j-rafique marked this pull request as ready for review May 4, 2026 11:54
@roomote-v0
Copy link
Copy Markdown

roomote-v0 Bot commented May 4, 2026

Rooviewer Clock   See task

All previously flagged issues have been addressed. No new issues found.

  • SelectTicketForBucket is missing the domainTicketRank domain separator in its hash input, breaking domain separation for ticket ranking (the constant is declared but never used)
  • AssignChallengerTargetsWithCandidates early-exit condition uses raw len(selectedTargets) instead of the deduplicated count, which can over-assign targets if the input contains duplicates or empty strings
Previous reviews

Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues.

Comment thread pkg/storagechallenge/deterministic/lep6.go Outdated
Comment thread pkg/storagechallenge/deterministic/lep6.go
@j-rafique j-rafique force-pushed the supernode/LEP-6-chain-client-extensions branch 2 times, most recently from 38849ea to fd7466f Compare May 4, 2026 12:03
Introduces pkg/storagechallenge/deterministic/lep6.go, the off-chain
computation library shared by the storage_challenge runtime, recheck
service, and self-healing dispatcher. Every function is pure (no I/O,
no clock, no goroutines) so independent reporters challenging the same
(target, ticket) pair produce byte-identical StorageProofResult fields.

Functions land in two categories:

CHAIN-MIRRORED (must match lumera/x/audit/v1/keeper/audit_peer_assignment.go
byte-for-byte; the chain re-runs them to validate MsgSubmitEpochReport):

  - SelectLEP6Targets — 1/3 deterministic target subset
    (SHA-256(seed||0x00||account||0x00||"challenge_target"),
    targetCount = ceil(N/divisor) clamped to [1, N])
  - PairChallengerToTarget / AssignChallengerTargets — challenger->target
    pairing (label "pair"), with no-self and lex tie-break

SUPERNODE-CANONICAL (chain stores outputs as opaque strings; this file
defines the canonical encoding all reporters must use to stay in lockstep):

  - ClassifyTicketBucket — RECENT/OLD bucket classification using
    Action.BlockHeight (Action.UpdatedHeight does not exist; see
    docs/plans/LEP6_SUPERNODE_IMPLEMENTATION_PLAN.md "Resolved Decision 3")
  - SelectTicketForBucket — deterministic per-(target,bucket) ticket pick
    with excluded-set support for active heal ops
  - SelectArtifactClass — LEP-6 §10 weighted roll (20% INDEX / 80% SYMBOL)
    with deterministic fallback when a class has no artifacts
  - SelectArtifactOrdinal — uniform ordinal mod artifactCount
  - ComputeMultiRangeOffsets — k=4 range offsets in [0, size-rangeLen)
  - ComputeCompoundChallengeHash — BLAKE3 over concat of slices in offset
    order (lukechampine.com/blake3 to match the chain's library)
  - DerivationInputHash — canonical hex of derivation inputs
  - TranscriptHash — full canonical transcript identifier with sorted
    observer ids; struct-input form prevents field-order mistakes

Domain separators ("challenge_target", "pair", "ticket_rank",
"artifact_class", "artifact_ordinal", "range_offset",
"derivation_input", "transcript") and enum string forms ("INDEX"/
"SYMBOL", "RECENT"/"OLD"/"PROBATION"/"RECHECK") are package
constants; freezing them prevents accidental drift between callers and
tests. Any change is a protocol-level break that requires versioning.

Tests:
  - TestStorageTruthAssignmentHash_KnownVector locks the byte-level SHA-256
    composition against an independent computation, guaranteeing the
    chain-mirrored helper has not drifted.
  - TestSelectLEP6Targets_OneThirdCoverage_AssignmentMatchesChain uses the
    chain's own audit_peer_assignment_test.go fixture
    (seed="01234567890123456789012345678901", active={sn-a..sn-f},
    divisor=3) — output {sn-f, sn-e}.
  - TestAssignChallengerTargets_KnownAssignment locks the full pairing
    {sn-a -> sn-f, sn-b -> sn-e}.
  - TestSelectArtifactClass_WeightedDistribution validates ~20% INDEX
    over 5000 draws (±2% tolerance).
  - Determinism, sensitivity, error-path, and out-of-bounds tests for
    every primitive.

Verified: `go test ./pkg/storagechallenge/deterministic/...` passes; the
existing deterministic_test.go pre-LEP-6 tests continue to pass.
@j-rafique j-rafique force-pushed the supernode/LEP-6-deterministic-primitives branch from 0dc9475 to af43dd8 Compare May 4, 2026 12:05
@j-rafique j-rafique changed the title feat(storagechallenge): add LEP-6 deterministic primitives (PR2) feat(storagechallenge): add LEP-6 deterministic primitives May 4, 2026
@j-rafique j-rafique merged commit 3024949 into supernode/LEP-6-chain-client-extensions May 4, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant