MCPcopy
hub / github.com/QuipNetwork/quip-protocol

github.com/QuipNetwork/quip-protocol @v0.2.0 sqlite

repository ↗ · DeepWiki ↗ · release v0.2.0 ↗
3,344 symbols 14,236 edges 254 files 2,024 documented · 61%
README

quip-miner

Experimental software. Use at your own risk. No production warranties.

A Python mining stack for the quip-protocol-rs Substrate chain. Drives CPU SA, GPU (CUDA / Metal / Modal), and QPU (D-Wave) miners against the chain's QuantumPow pallet — fetch the mining snapshot at each new chain head, search for valid Ising solutions, submit QuantumPow.submit_proof extrinsics, repeat.

This is the v0.2 line of the repository (formerly quip-protocol). In v0.1 this codebase shipped its own consensus, P2P (QUIC), block store, REST API, and SPHINCS+ block signer. v0.2 removes all of that — the chain is the source of truth, miners attach to it.

Architecture

                              chain (substrate)
                                     │
                              ws://localhost:9944
                                     │
                  ┌──────────────────┴──────────────────┐
                  │       SubstrateClient (read)         │
                  │   - get_mining_snapshot              │
                  │   - subscribe_new_heads              │
                  │   - submit_extrinsic                 │
                  └──────────────────┬──────────────────┘
                                     │
                  ┌──────────────────┴──────────────────┐
                  │  SubstrateMinerController            │
                  │   - on new head: cancel + fetch +    │
                  │     dispatch                         │
                  │   - on result: encode + submit       │
                  │   - classify receipts                │
                  └──────┬────────────────────┬──────────┘
                         │                    │
                  ┌──────┴──────┐      ┌──────┴──────┐
                  │ MinerCore   │      │ TelemetryApi│
                  │ - handles[] │      │ /api/v1/*   │
                  │ - stats     │      └─────────────┘
                  │ - descriptor│
                  └──────┬──────┘
                         │
                  MinerHandle (per worker process)
                         │
                  BaseMiner.mine_work_item
                  (CPU SA / GPU CUDA|Metal|Modal / QPU)

Component responsibilities (shared/):

module role
signer.py Abstract Signer + Sr25519Signer. Phase 7 adds HybridSigner (sr25519 + ML-DSA-44).
keystore.py sr25519 keystore (0o600 JSON; plaintext seed for dev).
substrate_client.py py-substrate-interface async wrapper; state_call for the mining snapshot.
substrate_types.py SubstrateMiningContext, SubstrateDifficulty, MinerInfo, ExtrinsicReceipt.
substrate_submitter.py MiningResultQuantumProof SCALE encoding + submission.
substrate_miner_controller.py Head subscription, snapshot fetch, dispatch, receipt classification.
miner_core.py Owns persistent MinerHandle workers, hardware descriptor cache, aggregate stats.
miner_bootstrap.py Idempotent fund + register pipeline.
telemetry_api.py HTTP REST surface (/api/v1/status, /system, /stats, /block/*).
base_miner.py Protocol-neutral mine_work_item(context, stop_event) loop.
miner_worker.py 2-process worker scaffolding (parent ↔ child mp.Queue + stop_event).
quantum_proof_of_work.py derive_nonce, generate_ising_model_from_nonce, evaluate_sampleset.

Standalone scripts at repo root:

file role
quip_cli.py quip-miner CLI dispatch (keygen / bootstrap / cpu / gpu / qpu).

Installation

python3 -m venv .quip
source .quip/bin/activate
pip install -U pip setuptools wheel
pip install -e .

Dependencies pulled in by pyproject.toml: - substrate-interface>=1.7.4, scalecodec>=1.2 — chain RPC + SCALE - dwave-ocean-sdk>=9.0.0,<10, numpy>=1.24.0 — Ising sampling - aiohttp>=3.9.0 — telemetry server + faucet - click>=8.1.7 — CLI - blake3>=1.0.5 — nonce derivation

D-Wave QPU access requires DWAVE_API_KEY in .env (loaded via python-dotenv).

Quick start

In one terminal, bring up the chain:

cd ../quip-protocol-rs
docker compose up -d
docker compose logs -f node1   # confirm blocks being produced

The dev faucet now lives in its own repository (gitlab.com/quip.network/faucet); local-network setup (node + faucet + chain seeding) is handled by the testing repo at nodes.quip.network. Point the miner at a running faucet with --faucet-url; it self-funds and self-registers on first run.

Bootstrap a miner account (generates a keystore, funds it via the faucet, sudo-seeds Difficulty + DefaultTopology on a fresh chain, then submits register_miner):

quip-miner bootstrap \
    --node-url ws://localhost:9944 \
    --faucet-url http://127.0.0.1:8087 \
    --seed-chain

Run the miner:

quip-miner cpu \
    --node-url ws://localhost:9944 \
    --num-cpus 4 \
    --topology zephyr:9,2 \
    --rest-port 8086

In a third terminal, watch chain events for QuantumPow.ProofAccepted (via polkadot.js pointed at ws://localhost:9944), or hit the local telemetry API:

curl http://localhost:8086/api/v1/status   | jq
curl http://localhost:8086/api/v1/stats    | jq
curl http://localhost:8086/api/v1/system   | jq

CLI reference

quip-miner keygen

Generate a fresh sr25519 signing key. Writes a 0o600 JSON keystore with the seed in plaintext (passphrase-encrypted keystores ship in Phase 7).

quip-miner keygen --out ~/.quip-miner/signing.json

quip-miner bootstrap

Idempotent setup: generate keystore (if missing) → request funds from the faucet → submit register_miner. With --seed-chain, also sudo-submits set_difficulty + register_topology if missing.

quip-miner bootstrap \
    --node-url ws://localhost:9944 \
    --signer-key ~/.quip-miner/signing.json \
    --faucet-url http://127.0.0.1:8087 \
    --seed-chain \
    --seed-topology 9,2

Re-runs are no-ops that just verify state.

quip-miner cpu | gpu | qpu

Run the mining controller. All three subcommands share these flags:

  • --node-url ws://... (required) — substrate WS endpoint
  • --signer-key ~/.quip-miner/signing.json — keystore path
  • --topology zephyr:M,T — sampler topology (defaults to zephyr:9,2)
  • --rest-port 8086 — HTTP telemetry port (-1 disables)

The cpu subcommand adds --num-cpus N; gpu adds --gpu-backend {local,metal,modal}; qpu adds --qpu-type and --daily-budget.

Topology binding is enforced at startup: the CLI hashes the configured topology with the same blake2_256(SCALE((sorted_nodes, canonical_edges))) recipe the chain uses, and refuses to start if the hash doesn't match the chain's registered topology.

Telemetry REST API

GET  /health
GET  /api/v1/status                        chain head + miner identity + is_mining
GET  /api/v1/system                        hardware descriptor (cached)
GET  /api/v1/stats                         aggregate MinerCore + controller stats
GET  /api/v1/block/latest                  substrate-fetched chain head
GET  /api/v1/block/{n}                     substrate-fetched block by number
GET  /api/v1/block/{n}/header              header subset
POST /api/v1/solve                         disabled in v0.2 (was direct DWave sample)

Response envelope: {"success": bool, "data": ..., "error": ..., "timestamp": int}.

The legacy /api/v1/peers, /api/v1/join, /api/v1/gossip, /api/v1/heartbeat, and POST /api/v1/block paths are removed — they were P2P / consensus surfaces with no equivalent in substrate mode. The legacy /telemetry/* SSE stream and per-peer aggregator also moved out; consumers should switch to substrate-side events and Prometheus (http://localhost:9615/metrics).

Topology

Mining works against any BoundedVec-bounded graph registered on chain (QuantumPow.RegisteredTopologies). The CLI's --topology zephyr:M,T constructs a dwave-networkx Zephyr graph; the chain's pallets/quantum-pow/src/topology.rs::hash_topology canonicalizes and blake2_256-hashes the result.

bootstrap --seed-chain --seed-topology 9,2 registers Zephyr Z(9,2) (1368 nodes / 7692 edges — the legacy default that matches the chain's difficulty calibration of max_energy_milli=-2_500_000). Smaller graphs (Z(2,2), Z(3,2)) work too but need their own difficulty calibration since their ground-state energy range is much narrower.

Running tests

python -m pytest tests/ -v

Integration tests against the docker chain auto-skip if ws://localhost:9944 isn't reachable. The end-to-end controller test (test_controller_submits_proof_end_to_end) bootstraps inline and asserts at least one QuantumPow.ProofAccepted event lands within 120 seconds.

The cross-language nonce-parity test (test_derive_nonce_parity.py) reads crates/quantum-validation/tests/fixtures/python_parity.json from a sibling quip-protocol-rs checkout. Set QUIP_RUST_FIXTURE_DIR if your checkout is elsewhere.

What changed from v0.1

Removed entirely:

  • The local blockchain stack: shared/block.py, shared/node.py, shared/network_node.py, shared/block_store.py, shared/block_synchronizer.py, shared/block_requirements.py, genesis_block_public.json.
  • The P2P stack: QUIC client/server, SWIM failure detector, peer scorer / ban list, gossip telemetry aggregator, sync wire codecs.
  • The legacy signing path: SPHINCS+ block signer + certificate manager.
  • CLI: quip-network-node and quip-network-simulator are gone. Use quip-miner instead.

Kept (with rewired backends):

  • /api/v1/status, /system, /stats, /block/* (now substrate-backed)
  • The 2-process worker model (MinerHandle ↔ child mp.Queue + stop_event)
  • The Ising sampling code (BaseMiner.mine_work_item, quantum_proof_of_work.*, CPU/GPU/QPU subclasses)
  • The hardware descriptor / aggregate stats (now exposed via MinerCore)

Migration:

  • A v0.1 miner that ran a single mining node now runs a chain node (quip-protocol-rs docker compose) + quip-miner cpu|gpu|qpu against it.
  • Mining rewards now accrue on chain to the registered sr25519 account, not as v0.1 block-proposer credit.

License

AGPL-3.0-or-later. See LICENSE.

Core symbols most depended-on inside this repo

generate_ising_model_from_nonce
called by 58
shared/quantum_proof_of_work.py
close
called by 47
tests/_metal_stream_fakes.py
pop
called by 44
shared/ising_feeder.py
run
called by 40
shared/stats_snapshot.py
should_log
called by 33
QPU/dwave_miner.py
open
called by 32
shared/mempool_types.py
_run
called by 30
substrate/client.py
edges
called by 28
dwave_topologies/topologies/zephyr.py

Shape

Function 1,943
Method 1,089
Class 309
Route 3

Languages

Python100%

Modules by API surface

tests/test_quip_cli.py91 symbols
tests/test_substrate_miner_controller.py84 symbols
substrate/client.py75 symbols
tests/test_submit_tip_and_retry.py67 symbols
tests/test_miner_config.py64 symbols
shared/base_miner.py63 symbols
quip_cli.py58 symbols
tests/test_base_miner_pump.py56 symbols
tests/test_mine_work_item.py53 symbols
substrate/miner_controller.py52 symbols
shared/mempool_types.py44 symbols
tests/test_metal_scheduler.py42 symbols

Dependencies from manifests, versioned

aiohttp3.9.0 · 1×
blake31.0.5 · 1×
click8.1.7 · 1×
cupy-cuda12x13.0.0 · 1×
dilithium-py1.0 · 1×
dwave-ocean-sdk6.0.0 · 1×
hashsigs0.0.2 · 1×
numpy1.24.0 · 1×
python-dotenv1.0.0 · 1×
scalecodec1.2 · 1×
substrate-interface1.7.4 · 1×
tomli2.0.1 · 1×

For agents

$ claude mcp add quip-protocol \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact