Skip to content

Releases: BitMind-AI/bitmind-subnet

Release 4.6.0

02 Apr 22:11
4f7519e

Choose a tag to compare

feat: Discriminator Verticals & Miner Performance CLI

Summary

Introduces the vertical axis to the discriminator competition (starting with image:human), adds a self-service performance endpoint for miners, adjusts incentive allocations, and cleans up deprecated code.

Changes

Vertical support in model uploads

  • gascli d push now accepts --vertical human (only valid with --modality image).
  • Client-side guards in both gas/cli.py and push_model.py prevent invalid vertical+modality combinations before hitting the API.
  • gas/protocol/model_uploads.py renamed to gas/protocol/miner_requests.py to reflect its broader scope.

Miner performance CLI (gascli d perf)

  • New gascli d perf command lets miners query their own benchmark results via an Epistula-authenticated GAS API endpoint.
  • Output shows SN34 score (with progress bar), MCC, Brier, modality, vertical, and elapsed time for running/queued jobs.
  • Supports --modality and --vertical filters.
  • Core HTTP logic lives in gas/protocol/miner_requests.py; CLI handles wallet loading, auth, and formatting.

Incentive allocation adjustment

  • Image allocation increased from 23% → 28.5% to accommodate the new image:human vertical (~17.5% of image rewards).
  • Video allocation adjusted from 29% → 23.5%.
  • Burn, audio, and generator percentages unchanged.

Fix: Non-resumable upload flow and silent 409 handling

The upload flow (push_model.py / upload_single_modality) had no way to distinguish a genuine failure from "your model was already accepted by the server." Miners who re-ran the script after a partial failure (e.g. chain registration timed out) would hit a 409 from /upload/presigned and receive an opaque error, unable to proceed.

What was wrong: The server returns 409 when the file hash is already in an accepted state (uploaded, downloading, validating, examining, or confirmed). Both 409 and genuine errors were handled identically — print("FAILED") and exit — even when the model was already on the server and the miner just needed to retry blockchain registration.

Fix: upload_single_modality in gas/protocol/miner_requests.py now returns an already_uploaded: True flag on 409. push_separate_models in push_model.py checks this per modality and prints a clear, actionable message:

⚠️  Video model already uploaded — skipping (model is already accepted by the server)
❌  Cannot retrieve r2_key for already-uploaded video model. Re-run with the
    original r2_key or wait for the current upload to be processed.

Note: The miner still can't fully auto-resume from a 409 because the server doesn't return the original r2_key on conflict (by design — information leak). A full solution would require a "status lookup by hash" endpoint that returns the r2_key for models owned by the requesting hotkey.

Release 4.5.6

21 Mar 20:01
298a9e5

Choose a tag to compare

C2PA trust anchor validation for c2pa-python >= 0.29.0

Background

c2pa-python==0.29.0 (released March 17 2026) changed c2pa-rs so that trust anchor checking is always enforced by default. Any certificate not chaining to a root CA in c2pa-rs's built-in store fires signingCredential.untrusted and hard-fails validation.

We had pinned c2pa-python>=0.25.0,<0.29.0 as a short-term workaround. This restores previous behavior but leaves a cert-forgery gap: our code only string-matched on the issuer field, which an attacker could fake with a self-signed cert set to "Stability AI Ltd".

What this PR does

1. Extracts and saves trust anchor PEM files

Scanned miner-submitted media in /workspace/.cache/sn34 (88k entries, source_type = 'miner') to find one sample file per AI provider. Extracted the full DER certificate chains embedded in each file's C2PA JUMBF box and saved them to gas/verification/trust_anchors/.

All major providers turned out to use private or non-CAI root CAs that are not in c2pa-rs's built-in store:

Provider Cert chain root File
Stability AI GlobalSign Root CA - R6 (via GlobalSign GCC R6 SMIME CA 2023) stability_ai.pem
Runway (pre-Gen4) GlobalSign Root CA - R6 (same intermediate) runway.pem
Runway Gen4 CN=Stability AI, O=Stability AI, C=US (private self-signed) runway_gen4.pem
Black Forest Labs GlobalSign Root CA - R6 (same intermediate) black_forest_labs.pem
Microsoft CN=Microsoft Supply Chain RSA Root CA 2022 (private self-signed) microsoft.pem
OpenAI (via Truepic) CN=Truepic WebClaimSigningCA chain openai_truepic.pem
Adobe CN=Adobe Product Services G4 chain adobe.pem
Google CN=Google C2PA Root CA G3 (fetched from pki.goog/c2pa/root-g3.crt) google_c2pa.pem

GlobalSign Root CA - R6 was sourced from the certifi bundle. Google's C2PA Root CA G3 was fetched directly from Google's PKI at http://pki.goog/c2pa/root-g3.crt.

2. Updates c2pa_verification.py

Three additions at the top of the file, zero changes to existing verification logic:

  • _load_trust_anchors() — concatenates all PEM files at import time into a single string
  • _TRUST_ANCHORS_PEM / _C2PA_HAS_CONTEXT_API — cached module-level constants (no per-call file I/O)
  • _open_c2pa_reader(file_path) — transparent wrapper around c2pa.Reader:
    • On >= 0.29.0: builds a Settings object with user_anchors (additive — preserves the built-in store) and wraps the reader in a Context
    • On < 0.29.0: returns a bare c2pa.Reader, identical to previous behaviour

The one-line change in verify_c2pa():

# before
with c2pa.Reader(file_path) as reader:

# after
with _open_c2pa_reader(file_path) as reader:

3. Bumps the version pin

# pyproject.toml
- "c2pa-python>=0.25.0",
+ "c2pa-python>=0.29.0",

Verification

Ran gascli g verify-c2pa against one sample file per provider on c2pa-python 0.29.0:

Adobe         (Adobe Inc.)
Black Forest Labs  (Black Forest Labs Inc.)
Runway Gen4   (Runway — private Stability AI root)
Google        (Google LLC — Google C2PA Root CA G3)
Google        (Google C2PA Core Generator Library)
Microsoft     (Microsoft Corporation — video)
Microsoft     (Microsoft Corporation — image)
OpenAI        (Sora / Truepic chain)
OpenAI        (OpenAI-API)
Runway        (RUNWAY AI, INC. — pre-Gen4)

One Stability AI sample showed assertion.dataHash.mismatch — the cached file was modified after signing, which is correct behaviour (hash mismatch ≠ trust failure).

Security improvement

With c2pa-python>=0.25.0,<0.29.0, c2pa-rs skipped the trust chain check entirely. Our code fell back to string-matching on issuer, meaning an attacker could submit media signed with their own self-signed cert and set issuer = "Stability AI Ltd" to pass validation.

With this PR, c2pa-rs performs full cryptographic chain verification against the extracted root certs. Forging a cert that chains to CN=Stability AI, O=Stability AI (Runway Gen4's root) or GlobalSign Root CA - R6 requires breaking RSA-2048/PSS — the issuer string alone is no longer sufficient.

Release 4.5.2

20 Feb 21:12
f3f504c

Choose a tag to compare

Validators can now run as Docker containers alongside the existing pm2 setup. pm2 remains the default — Docker is an explicit opt-in via --docker on all gascli validator commands.

Running with pm2 (default)

gascli v start
gascli v stop
gascli v logs

Running with Docker

gascli v start  --docker
gascli v stop   --docker
gascli v delete --docker
gascli v status --docker
gascli v logs   --docker

Or directly via Compose:

docker compose --env-file .env.validator up -d

Architecture

Three containers share a single bitmind-subnet-validator image, each running one service (controlled by the SERVICE env var):

Container Role
validator Core validation loop, FastAPI callback server
generator Image/video generation (GPU-enabled)
data Dataset downloads and cache management

Configuration

.env.validator is the single source of truth for both container environment and Compose variable substitution (bind-mount paths, ports, etc.). Copy the template and fill in your details:

cp .env.validator.template .env.validator

Key fields:

Variable Description
WALLET_PATH Host path to your Bittensor wallets directory
WALLET_NAME / WALLET_HOTKEY Only that wallet's subdirectory is bind-mounted
BT_LOGGING_LOGGING_DIR Base path for validator state and Bittensor logs
SN34_CACHE_DIR Model/data cache — shared between pm2 and Docker, no re-downloading when switching
HF_HOME Hugging Face cache — also shared with pm2
CALLBACK_PORT Port miners call back to; exposed via network_mode: host
NETUID Auto-derived from CHAIN_ENDPOINT; set explicitly to override

Persistent state

Scores, challenge tasks, and Bittensor logs are bind-mounted from the host under BT_LOGGING_LOGGING_DIR/WALLET_NAME/WALLET_HOTKEY/ and survive container restarts.

Automatic updates

A cron-friendly docker/autoupdate.sh script pulls the latest image and restarts containers:

*/5 * * * * /path/to/bitmind-subnet/docker/autoupdate.sh >> /var/log/bitmind-docker-update.log 2>&1

Viewing logs

# via gascli
gascli v logs --docker

# directly (per service)
docker compose logs -f validator   # or generator, data

Release 4.4.7

12 Feb 06:33

Choose a tag to compare

Release notes: 4.4.1 – 4.4.7

4.4.1 (30 Jan 2026)

  • Validator weight normalization: Only assign non-zero weights to UIDs in the active set; explicitly zero out weights for inactive generative miners before scaling.

4.4.2 (31 Jan 2026)

  • C2PA verification: Broader C2PA issuer handling so more certificate issuers are accepted as trusted.
  • Allow all certificate issuers to be treated as CA issuers where appropriate.
  • Remove redundant issuer logic and consolidate issuer handling.
  • Increase C2PA options and clean up multiple issuer versions.

4.4.3 (3 Feb 2026)

  • New upload endpoint for discriminative miner model uploads (neurons/discriminator/push_model.py).
  • Validator: Decrease burn (burn rate reduced).

4.4.4 (4 Feb 2026)

  • Generator prompt sampling: Keep remove=False so prompts are not removed when sampled; use threading.Lock for thread-safe prompt sampling.
  • Content cache and uploads: New content DB and content manager support plus a new upload path used by the data service.
  • Config: New options for content/upload behavior (see .env.validator.template).
  • Docs: Updates to Discriminative-Mining, ONNX, and Validating.

4.4.5 (6 Feb 2026)

  • Generator rewards: Use a 2-hour lookback window for recent verified miner media when computing generator base rewards (eligibility and score stability).
  • Content cache: Content DB and content manager extended to support the new lookback and verification stats.

4.4.6 (6 Feb 2026)

  • Stability AI service: Fix request headers for the Stability AI miner service so API calls succeed.
  • Webhooks / logging: Remove unused has_c2pa key from logging; keep useful logging; reduce log noise.
  • Metagraph / validator: Minor adjustments for consistency and clarity.

4.4.7 (8 Feb 2026)

  • Verification stats: Add support for failed miner media in the lookback window.
    • New get_recent_failed_miner_media() in content DB and content manager (default 2-hour lookback).
    • New get_verification_stats_last_n_hours() to compute pass/fail counts and pass rate per miner over the last N hours (for generator base rewards and eligibility).
  • Content manager: New helper _build_verification_stats_from_verified_and_failed() to build per-miner verification stats from both verified and failed media.
  • Validator: Uses the new verification stats and failed-media lookback for more accurate generator rewards and eligibility.

Release 4.4.0

31 Jan 06:30
6e593ac

Choose a tag to compare

Summary

  • Fix generator reward logic for sharper penalties when generative miners stop responding to queries
  • Improve media format detection with proper ftyp-based MP4 detection and support for additional formats
  • Fix file format handling - detect actual format from magic bytes instead of hardcoding extensions/content-types
  • Add dynamic escrow address fetching from the API with fallback to defaults
  • Add prompt modality tracking to ensure prompts are matched to their intended modality
  • Add prompt cache cleanup to delete prompts after use, preventing unbounded cache growth
  • Add detailed error responses for generative callback failures so miners can debug issues
  • Add webhook stats tracking for miners to monitor success/failure rates per validator
  • Add C2PA verification CLI for testing C2PA credentials on local files
  • Remove LocalService from registry (since it doesn't produce C2PA-signed content)

Changes

Generator Miner Rewards Fix

  • Fixed bug where include_all=True was double-counting already-rewarded media in verification stats
  • Changed reward eligibility from union to intersection: miners must now have both local verified submissions and benchmark results to receive rewards
  • Changed base reward default from 1e-4 to 0 for generators without verified submissions
  • Increased EMA alpha from 0.2 to 0.5 for more aggressive score decay on inactive miners
  • Added hard cutoff to zero out scores for generators not active within the liveness window

Media Format Detection (#311)

  • Fixed MP4 detection by checking for ftyp at offset 4 instead of hardcoded box sizes
  • Consolidated all ftyp-based format detection to fix unreachable M4A code path
  • Added support for new image formats: HEIC/HEIF, AVIF, GIF, BMP, TIFF
  • Added support for new video formats: MOV, 3GP, AVI
  • Added support for audio formats: MP3, WAV, FLAC, OGG, M4A
  • Added length checks to prevent index errors on short data
  • Improved JPEG detection with 3-byte signature

Dynamic Escrow Addresses (#322)

  • Added new get_escrow_addresses() function to fetch escrow addresses from the gas-api to provide the option to punish weight copiers.
  • Validators now dynamically fetch video_escrow, image_escrow, and audio_escrow addresses
  • Escrow address eligibility based validators provably running latest SN code.

Prompt Modality Support

  • Added modality column to prompts table (image, video, audio)
  • Database migration automatically adds column to existing installations
  • Fixed database migration order to prevent "no such column: modality" errors on existing databases
  • Prompts are now stored with their intended modality when generated
  • Challenge manager selects modality first, then samples matching prompts

Prompt Cache Cleanup

  • Fixed remove parameter in prompt sampling to actually delete prompts instead of just incrementing used_count
  • Added min_prompts_threshold (default 100) to prevent running out of prompts
  • Enabled prompt cleanup in generative challenge manager - prompts are now deleted after use (if enough remain)

Generative Callback Error Responses

  • Miners now receive detailed error messages when their submissions are rejected:
    • 400 - Empty binary payload for empty uploads
    • 400 - Corrupted or unreadable media for invalid media files
    • 400 - Duplicate content detected for perceptual hash matches
    • 400 - C2PA verification failed: no C2PA manifest for missing credentials
    • 400 - C2PA verification failed: untrusted issuer for non-trusted sources
  • Previously, all validation failures returned 200 OK silently, making it impossible for miners to debug issues
  • Made c2pa a hard dependency - removed conditional C2PA_AVAILABLE checks
  • Cleaned up inline imports, moved all imports to module scope

Miner Webhook Stats Tracking

  • Added WebhookStatsTracker to track webhook success/failure rates per validator IP
  • Stats are persisted to ~/.bitmind/webhook_stats.json and survive restarts
  • Automatic behaviors:
    • Saves to disk every 60 seconds (debounced to avoid excessive I/O)
    • Prints summary to logs every 5 minutes
    • Daily rotation at midnight - archives to webhook_stats_archive/webhook_stats_YYYY-MM-DD.json
    • Auto-cleanup of archives older than 7 days
  • Failure types are categorized:
    • empty_payload - validator received empty data
    • connection_timeout - connection timed out
    • connection_error - network/connection issues
    • http_400, http_401, http_404, http_500 - HTTP status codes
  • Helper functions available:
    • print_webhook_stats() - print summary to logs
    • get_webhook_stats_json() - get stats as dict
    • reset_webhook_stats() - clear all stats

LocalService Removed from Service Registry

  • LocalService (local Stable Diffusion/AnimateDiff) removed from SERVICE_MAP
  • Reason: LocalService doesn't produce C2PA-signed content, which validators now require
  • The service class remains in the codebase for potential future use
  • Valid services are now: openai, openrouter, stabilityai, or none
  • If no valid service is configured for a modality, requests for that modality will be rejected
  • Miners still free to generate whatever

C2PA Verification CLI

  • Added gascli generator verify-c2pa (standalone helper script at neurons/generator/helper/verify_c2pa.py) command for gen miners to test local files for C2PA credentials
  • Useful for miners to verify their generated content has valid C2PA before sending to validators
  • Supports --verbose for detailed output and --json for machine-readable output

Release 4.3.0

04 Dec 05:29
a017663

Choose a tag to compare

This release introduces c2pa verification for miner submissions (+ the relevant support on the generative miner side), an upgraded prompt generation pipeline, and fixes for weight normalization in the validator.

Generative Miner Data Verification

New modules in gas/verification/:

  • c2pa_verification.py: Validates C2PA content credentials from miner-submitted media. Checks that content originates from trusted AI generators (OpenAI, Google, Adobe, Microsoft, Stability AI, Midjourney, Anthropic). Content without valid C2PA from trusted issuers is rejected.

  • duplicate_detection.py: Implements perceptual hashing (pHash) for images and frame-based hashing for videos. Includes crop-resistant hash segments. Configurable Hamming distance threshold (default: 8) for near-duplicate matching.

Miner Service Configuration

  • Added IMAGE_SERVICE and VIDEO_SERVICE environment variables to specify which generation service to use per modality
  • Valid options: openai, openrouter, local, none
  • Setting none disables that modality entirely
  • Prevents loading unnecessary local models when using API services
  • Conditional model loading based on configured services

Prompt Generation Pipeline

  • Replaced BLIP-2 with Qwen2.5-VL-3B-Instruct for image annotation
  • Optional flash attention support for faster inference
  • New modules for model-specific prompt styles (model_prompt_styles.py) and prompt modifiers (prompt_modifiers.py)
  • Increased max token output from 20 to 256 for richer descriptions

Challenge Manager Improvements

  • Pre-storage validation rejects: duplicate content, content without valid C2PA, corrupted/unreadable media
  • Duplicate checks now scoped to same prompt ID to reduce overhead
  • Only validated content is stored and eligible for HuggingFace upload

Service Improvements

  • C2PA metadata preservation in OpenRouter and OpenAI services
  • Option to save generated media locally (MINER_SAVE_LOCALLY)
  • Default model changed to nanobanana pro for OpenRouter

Validator Weight Normalization Fix

  • Fixed burn rate calculation by excluding special UIDs (burn, image escrow, video escrow) from weight normalization (previously burning more than .7)
  • Added null check for empty generator rewards
  • Added logging for actual vs target burn rate verification

Dependencies

  • Added: c2pa-python>=0.25.0, imagehash>=4.3.1, qwen-vl-utils>=0.0.14
  • Updated: async-substrate-interface>=1.5.1
  • Optional: flash-attn>=2.7.0 (commented, for manual installation)

Breaking Changes

  • For now, miners must now produce content with valid C2PA credentials from trusted AI generators.
  • Duplicate submissions within the same prompt are rejected
  • Until we harden verification of open source model outputs, miners using local generation without C2PA embedding will have submissions rejected
  • Current services supported in c2pa checks:
OpenAI
Google
Adobe
Microsoft
Meta 
Shutterstock
Canva
Runway
Stability AI
Pika Labs

Reach out to the BitMind team if there are more services you'd like to have supported.

Release 4.2.0

31 Oct 01:28
172bb6d

Choose a tag to compare

  • Added Chrom1-HD to validator generation pipeline
  • Replaced local eval code with a gasbench wrapper
  • Single modality uploads for gascli d push (docs)
  • Better state/task tracking for generative tasks in validator

Release 4.1.7

31 Oct 01:26
626e0e8

Choose a tag to compare

Bugfix: Need to use the union of generator uids present in verification stats and fool rate stats to set weights for new generative miners

Release 4.1.6

02 Oct 11:19
98c99c9

Choose a tag to compare

Improved generative miner time-to-incentive and score stability.

Release 4.1.4

01 Oct 00:44
e5187b8

Choose a tag to compare

Burn off, generator rewards on, discriminator WTA split into image and video winners