Deterministic Trust Infrastructure for Bittensor
by Orthonode Infrastructure Labs
Thank you for your interest in contributing to INVARIANT. This document explains how to contribute effectively and what standards we hold all contributions to.
- Code of Conduct
- What We're Looking For
- Getting Started
- Development Setup
- Making Changes
- Testing Requirements
- Pull Request Process
- Coding Standards
- Documentation Standards
- Security Contributions
INVARIANT is a professional infrastructure project. All contributors are expected to:
- Be direct, precise, and technical in communications
- Critique ideas, not people
- Back claims with evidence or code
- Respect that determinism is a non-negotiable design principle — do not propose changes that introduce probabilistic or behavioral security where cryptographic guarantees are possible
- Respect the security-first posture — no shortcuts in gate logic, ever
- Gate engine improvements — performance, correctness, new attack vector coverage
- OAP engine refinements — scoring formula improvements, edge case handling
- Bittensor integration fixes — API compatibility updates, metagraph handling
- Test coverage — additional attack scenarios, edge cases, property-based tests
- Documentation — technical accuracy corrections, deployment guides, integration examples
- Rust crate — performance improvements, additional PyO3 bindings, benchmarks
- Scripts — wallet setup, subnet registration, deployment automation
- CI/CD — GitHub Actions workflows for automated test runs
- Benchmarks — additional throughput and latency measurements
- Changes that weaken the four-gate cryptographic guarantees
- Changes that introduce behavioral or probabilistic security where deterministic gates exist
- Features that require centralized infrastructure without a decentralization migration path
- UI/frontend work (INVARIANT is a protocol, not an application)
git clone https://github.com/orthonode/invariant.git
cd invariantgit checkout -b feat/your-feature-name
# or
git checkout -b fix/issue-description
# or
git checkout -b docs/what-you-are-documentingBranch naming conventions:
feat/— new featuresfix/— bug fixesdocs/— documentation onlytest/— test additions/improvementsperf/— performance improvementsrefactor/— code restructuring without behavior change
python -m venv venv
source venv/bin/activate # Linux/macOS
# or: venv\Scripts\activate # Windows
pip install -r requirements.txt
pip install pytest pytest-asyncio
# Verify everything works
python scripts/test_locally.py
pytest invariant/invariant/tests/ -v# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
# Install maturin
pip install maturin
# Build the Rust extension
cd invariant/invariant-gates
maturin develop --features python-ext --release
cd ../..
# Verify Rust backend active
python -c "
import sys
sys.path.insert(0, 'invariant/invariant/phase1_core')
from invariant_gates_bridge import using_rust
print('Rust:', using_rust())
"
# → Rust: True
# Run benchmarks
cd invariant/invariant-gates
cargo bench# Clone and build subtensor
git clone https://github.com/opentensor/subtensor.git
cd subtensor
cargo build -p node-subtensor --release --features pow-faucet
./target/release/node-subtensor --dev --one --validator --rpc-external --rpc-cors=all --rpc-methods=unsafe &
cd ..
# One-shot wallet + subnet + neuron registration for local dev
python instant_register.py
# Launch miner and validator (root-level runners)
python miner.py --wallet.name miner1 --wallet.hotkey default --netuid 1 --subtensor.network local --axon.port 8091
python validator.py --wallet.name validator1 --wallet.hotkey default --netuid 1 --subtensor.network localThe four-gate logic in invariant_gates.py and the Rust crate invariant-gates/src/verifier.rs must remain byte-for-byte equivalent. Any change to gate logic must:
- Be updated in both
invariant_gates.py(Python fallback) ANDinvariant-gates/src/(Rust) - Produce identical results on all existing test vectors
- Include new tests specifically covering the changed behavior
- Update
THREAT_MODEL.mdif the change affects any threat vector
The bridge (invariant_gates_bridge.py) must never contain gate logic — it is a routing layer only.
The OAP scoring formula in invariant_oap.py affects miner economics. Changes must:
- Include explicit before/after comparison of NTS values for representative scenarios
- Not introduce any path that allows NTS to exceed 100.0 or go below 0.0
- Not introduce any mechanism for silent NTS resets (the append-only guarantee is absolute)
- Update the
emission_weightformula documentation if the formula changes
Any change to miner.py or validator.py must:
- Be compatible with Bittensor v10+ (PascalCase API)
- Not break the graceful fallback for
serve_axonCustom Error 10 - Maintain the per-miner unique task dispatch pattern (not broadcast)
- Be tested against a local subtensor node before PR submission
All PRs must pass all existing tests. No exceptions.
# Full test suite — must all pass
pytest invariant/invariant/tests/ -v
# Local harness — must complete without failure
python scripts/test_locally.py
# Bridge self-test
python invariant/invariant/phase1_core/invariant_gates_bridge.py- Any new gate behavior → new test in
TestGateEngine - Any new OAP behavior → new test in
TestOAPEngine - Any new attack vector addressed → new test in
TestGateEnginewith explicit assertion on which gate fires and which gate number is returned - Any performance-sensitive change → updated throughput assertion in
TestThroughput
# GOOD — isolated, explicit, documents the attack and defense
def test_attack_counter_rollback(self, verifier, agent_hex, model_hex):
"""Submitting a lower counter is blocked at Gate 3 (replay protection)."""
r_high = build_receipt(agent_hex, model_hex, "t", "o", 500, 100, time.time())
r_low = build_receipt(agent_hex, model_hex, "t", "o", 3, 100, time.time())
assert GateResult.is_pass(verifier.verify(r_high)["result"])
result = verifier.verify(r_low)
assert result["result"] == GateResult.GATE3
assert result["gate_number"] == 3
# BAD — no assertion on which gate fired, no docstring, no counter isolation
def test_replay(self, verifier, receipt_factory):
r = receipt_factory()
verifier.verify(r)
result = verifier.verify(r)
assert result["result"] != "PASS" # too vague- All existing tests pass (
pytest invariant/invariant/tests/ -v) - Local harness passes (
python scripts/test_locally.py) - New tests added for new behavior
- Docstrings updated for any changed public functions
-
CHANGELOG.mdupdated under[Unreleased] - No new credentials, seed phrases, or wallet JSON files committed
-
.gitignoreincludes any new file patterns that should not be committed
## Summary
One paragraph explaining what this changes and why.
## Type
- [ ] feat (new feature)
- [ ] fix (bug fix)
- [ ] docs (documentation)
- [ ] test (test improvements)
- [ ] perf (performance)
- [ ] refactor (no behavior change)
## Testing
- Existing tests: all pass (pytest invariant/invariant/tests/ -v)
- New tests added: [list test names]
- Local harness: passes (python scripts/test_locally.py)
## Gate/OAP Impact
[If applicable: describe any change to gate logic, OAP scoring, or emission formula]
## Breaking Changes
[None / describe breaking changes]
PRs are reviewed for:
- Correctness — Does it do what it claims? Are edge cases handled?
- Security — Does it maintain or improve the cryptographic guarantees?
- Test coverage — Are the new behaviors tested with clear assertions?
- Determinism — Does it preserve deterministic behavior where determinism is required?
- Compatibility — Does it remain compatible with Python 3.10+ and Bittensor v10+?
- Documentation — Are public APIs documented? Is
CHANGELOG.mdupdated?
- Style: PEP 8, 100-character line limit
- Type hints: Required on all public function signatures
- Docstrings: Required on all public classes and functions
- Imports:
import xbeforefrom x import y; stdlib before third-party before local - Error handling: Explicit exception types; never bare
except: - Naming:
snake_casefor functions/variables,PascalCasefor classes,UPPER_CASEfor module-level constants
# GOOD
def derive_software_agent_id(
hotkey_ss58: str,
model_hash_hex: str,
registration_block: int,
) -> str:
"""
Derive a 64-char hex agent_id for a software-only miner.
Args:
hotkey_ss58: Bittensor hotkey in SS58 encoding.
model_hash_hex: Hex-encoded SHA-256 of the model identifier.
registration_block: Block number at which the miner registered.
Returns:
64-character lowercase hex string (32 bytes).
"""
# BAD — missing type hints, missing docstring, unclear naming
def get_id(h, m, b):
pass- Style:
cargo fmtbefore every commit - Lints:
cargo clippy -- -D warningsmust pass - Error handling:
Result<T, E>with descriptive error types; neverunwrap()in library code - Safety: No
unsafeblocks without explicit justification comment
# Run before every commit (Rust changes)
cd invariant/invariant-gates
cargo fmt
cargo clippy -- -D warnings
cargo test
cargo bench --no-run # ensure benchmarks compileFollow Conventional Commits:
type(scope): short description (max 72 chars)
Optional longer body explaining WHY, not WHAT.
The diff shows what changed; the commit message explains why.
Closes #123
Types: feat, fix, docs, test, perf, refactor, chore
Scopes: gates, oap, bridge, miner, validator, rust, tests, scripts, docs
Examples:
feat(oap): add scar decay for minor violations after 10 clean tempos
fix(bridge): use counter+1 in tamper test to avoid Gate 3 false positive
test(gates): add counter rollback attack scenario to TestGateEngine
perf(rust): use batch SHA-256 computation for verify_batch
All documentation claims must be verifiable. Do not write:
- "INVARIANT is the fastest subnet" (unverified superlative)
- "This is impossible to hack" (no security absolute)
- "Works on all chains" (scope not verified)
Write instead:
- "INVARIANT achieves <50µs per receipt on the Rust backend (benchmarked on commodity hardware)"
- "SHA-256 preimage attacks are computationally infeasible with current hardware"
- "INVARIANT is deployed on Bittensor and tested against Arbitrum Sepolia and TON Testnet"
All architecture diagrams use Mermaid syntax. Test diagrams at mermaid.live before committing.
All command examples must be tested on a clean environment before documentation is merged. Mark untested examples with # [UNTESTED] in a comment.
See SECURITY.md for the full vulnerability disclosure policy.
Summary: Do not open public GitHub issues for security vulnerabilities. Email security@orthonode.xyz with a description and proof-of-concept. We respond within 48 hours.
Security contributions that responsibly disclose gate bypass vulnerabilities, OAP score manipulation techniques, or cryptographic weaknesses will be credited in CHANGELOG.md and THREAT_MODEL.md.
- GitHub Issues — for bugs, feature requests, and documentation improvements
- GitHub Discussions — for design questions and architectural proposals
- Email —
contact@orthonode.xyzfor everything else
Thank you for helping make INVARIANT more robust, more secure, and more useful to the Bittensor ecosystem.
— Orthonode Infrastructure Labs