Repository navigation
fix(validator): make gateway authoritative and peer consensus opt-in - #310
Merged
Merged
Conversation
Cortex runs a centralized authoritative gateway: the master gateway is the authority for weights and a validator consumes /v1/weights/latest and submits the verified vector on-chain. The peer-root sample in _crosscheck was an unconditional precondition, so a single-validator deployment on a subnet that holds other permitted validators refused every tick with peer_consensus_unavailable and never submitted. Add Validator(peer_consensus=False) and the --peer-consensus CLI flag. With it off, _crosscheck returns True before it reads min_peer_sample. With it on, the peer path is unchanged, including PEER_ROOT_CONFLICT, PEER_SAMPLE_INSUFFICIENT and the min_peer_sample == 0 refusal. The local equivocation guard is preserved unconditionally: a validator whose own prior root for the epoch disagrees still refuses and dissents PEER_ROOT_CONFLICT. DissentReason values and the wire layout are untouched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem and behavior
Decision (project owner). Cortex runs a centralized authoritative gateway. The master gateway is the authority for weights: it serves
/v1/weights/latest,/v1/weights/{epoch}and/v1/bundle/{epoch}. Validators consume those endpoints and submit the weights on-chain. Peer-root consensus between independent validators is not part of this deployment model.Trigger. The production validator refused every tick and never submitted:
Verified on-chain fact. At block 9117927, netuid 100 has 7 hotkeys holding
validator_permit. In_crosscheck,others = validators - {own}is therefore never empty, so the earlyif not others: return Truenever fired and the peer-sample requirement could never be satisfied by a single-validator deployment. Reproduced identically with the new image (a7537eed) and the old image (070ad22b) — a policy mismatch, not a regression.Previous behavior. A peer-root sample of at least
min_peer_samplewas an unconditional precondition for submission whenever any other permitted validator existed. Lowering--min-peer-sampleto0could not bypass it (that path dissentsPeerSampleInsufficientby design).Resulting behavior.
Validatortakespeer_consensus: bool = Falseand the CLI gains--peer-consensus. With peer consensus off (the new default),_crosscheckreturnsTruebefore it ever readsmin_peer_sample. With--peer-consensus, the peer path is byte-for-byte the old policy.What changed
src/cortex/validator/service.py: new documentedpeer_consensusconstructor parameter;_crosscheckgates only the peer-sample requirement (if not self.peer_consensus or not others: return True).src/cortex/validator/__main__.py:--peer-consensusopt-in flag, help text stating the deployment model, passed through to the service.--peersand--min-peer-samplebehave exactly as before when the flag is on.docs/BUNDLE_SPEC.md§11.3 anddocs/external-miner/validators.md: deployment model stated; peer sample reclassified as opt-in hardening rather than deleted.scripts/check_repo.py: rotated thedocs/BUNDLE_SPEC.mdfrozen-spec SHA-256 pin to match the directed §11.3 edit (821a209b…→c7a43fca…). No wire format, no enum, no protocol text was changed — see "Public contract" below.Deliberately preserved
old = self.journal.evidence.local_root(body.epoch)block and theself.journal.evidence.root(..., local=True)write run unconditionally in both models. If our own prior root for an epoch disagrees, the validator still refuses and still persists aPEER_ROOT_CONFLICTdissent. That is self-consistency, not peer consensus.DissentReasonis untouched: no value renumbered, removed or reordered.RootStatement/Dissentlayouts, domains and the on-chain payload are unchanged.--peer-consensus,PEER_ROOT_CONFLICT,PEER_SAMPLE_INSUFFICIENTand themin_peer_sample == 0refusal are all still reachable and still tested.--peer-consensusgoverns only what this validator requires of others.Tests
test_multi_validator_requires_metagraph_authenticated_peer_sample(4-case parametrize incl.zero_sample) — kept, now explicitly enables peer consensus via thesigned_peershelper. Still assertsPEER_SAMPLE_INSUFFICIENT.test_peer_equivocation_persists_both_signed_roots_and_refuses_dispatch— passes with its assertions unchanged; it uses the sharedsigned_peershelper, which now setspeer_consensus=True(default for that helper).test_centralized_gateway_default_submits_without_a_peer_root_sample— peer consensus left off, metagraph contains other permitted validators (validator_permits={0, 2}); asserts the real outcome issubmitted, the real chain submission[(541, ((1, 65535),), 1)], the local root persisted, and no dissent.test_local_equivocation_still_refuses_dispatch_without_peer_consensus— no peers, peer consensus off, conflicting prior local root; asserts refusal andPEER_ROOT_CONFLICT.signed_peersgained apeer_consensus=Trueknob; no existing fixture changed meaning for other tests.Validation
uv run --no-sync ruff format --check src tests scripts152 files already formatteduv run --no-sync ruff check src tests scriptsAll checks passed!uv run --no-sync mypySuccess: no issues found in 83 source filesuv run --no-sync pytest -m 'not live' -q1114 passed in 36.04suv run --no-sync python scripts/check_repo.py --finalRepository contracts passed (final Python-only gate).uv run --no-sync python scripts/check_deploy.py --check-examplesPython images, roles, VM host and fail-closed pins validated; no services started.Before the spec-pin rotation, the suite reported
2 failed, 1112 passed, both fromtests/test_repo_contract.pyfrozen-spec hash assertions.origin/main(0874160) was verified clean in a scratch worktree (26 passed) first, confirming the two failures came from this PR's directed §11.3 edit and not from the base.scripts/check_repo.py --finalPublic contract
docs/external-miner/validators.md,docs/BUNDLE_SPEC.md§11.3)BASE_*/domain compatibility remain intact —DissentReasonvalues,RootStatement/Dissentencodings and signing domains are unchanged. The §11.3 edit is prose reclassifying the peer sample as opt-in and documenting the always-on local equivocation guard; thecheck_repo.pypin was rotated to the new file hash because that check detects any byte change, including a directed one.Greptile
@greptileai reviewRisk
Residual risk: a centralized gateway is a single point of authority for weights. With
--peer-consensusoff, nothing outside the gateway corroborates the root a validator signs and submits. A compromised or faulty gateway that produces a well-formed, correctly-signed bundle over verified trust files is submitted on-chain without independent peer corroboration. The mitigations that remain are: the independently pinned gateway public key, local owner-signed trust roots with version watermarks, full local recomputation of the final vector (Class A dissent still submits the locally recomputed vector), the owner/validator monopoly refusal, block-freshness and reorg rechecks, and the local equivocation guard. Peer cross-check remains available and unchanged for anyone running independently-operated validators: pass--peer-consensus.Emission impact: intended and immediate — the validator resumes submitting weights instead of refusing every tick. Rollback: revert this commit, or run with
--peer-consensusto restore the previous policy without a code change. No migration: no schema, wire or on-chain payload change; journals and evidence databases are compatible in both directions.🤖 Generated with Claude Code
Safe to merge.
What we checked:
Summary
Peer-root consensus is now an explicit opt-in for validator deployments using the authoritative gateway. The validator continues to require peer samples when opted in and retains its local equivocation protection in both modes.
Reviews (1) · Last reviewed commit: "fix(validator): make gateway authoritati..."