← Todos os posts

Técnico · Walkthrough

How to run a verifier: for yourself, or as a service

"Don't trust, verify" is only a real promise if you can run the verifier. On TensorCash you can: the verifier is open source, the proof a miner produces is self-contained, and standing up the thing that checks it is a documented, reproducible job.

There's one decision that shapes everything else, so make it first.

The dichotomy: for yourself, or as a service

It's the same open-source engine either way. What changes is who it answers for.

For yourselfAs a service
Who it servesyou — your node, your proofsmany consumers at once
Whytrust nobody for "the model ran""compute once, serve many"
Shapethe engine co-located with your nodethe engine behind an HTTP gateway
Reachone box, inwardminers, nodes, explorers, other validators

For yourself is the sovereign self-check: you re-check every block proof — or a single proof you didn't create — on your own machine, and trust no third party for the AI-execution claim. As a service turns that same engine outward: behind its HTTP gateway, one verifier you operate answers "did the work run, and which model?" for everyone who points at it.

Pick the half you need; the rest of this post covers both.

What the verifier actually checks

The verifier is a small ladder of checks, cheapest first, that ends in a verdict of GREEN / AMBER / RED:

  • quick and quick-smell — fast structural and statistical screens. These run on CPU.
  • pow — the proof-of-work over the inference output, checked on the proof alone, without chain context.
  • full — the complete check of a block's proof: it re-runs the claimed model on a GPU and checks that the replayed sequence and logits match. This is the "which model ran" assertion. logits runs just that replay, without the block checks.
  • model — the check behind a model registration: it audits the registered model and checks that its measured compute is consistent with the claimed difficulty.

So a verdict answers the two questions everything else on the chain rests on: did the work run, and which model produced it. (Model approvals themselves are operator-gated — a model check can land in a pending-review state for a human to approve or reject before it's trusted. Challenges against a registered model go through the same review.)

Run it for yourself

The sovereign setup co-locates the open-source verifier engine with your node, so every block your node accepts is re-checked on your own box — no third party in the loop. The core-validation-api stack is exactly that topology: node + your own verifier + a local gateway, no miner. It runs the full/model re-run on your own hardware, so it needs a GPU and the model, plus an OPERATOR_API_KEY (the verifier container exits without one) and a VERIFY_SHARED_API_KEY that keys the node-to-gateway calls. Chain and pruning come from a bitcoin.conf you mount at the data dir, and the core-node image's mining supervisor needs a compose override to silence — so bringing this up cleanly is a from-the-repo job, covered in How to run a node.

If you'd rather just stand up the engine on its own to verify proofs — without a node attached — run it directly from source; that's the next section. And if you want to mine on the same box too, the full-sovereignty stack core-miner-validation-api adds the worker — the other end of the mining sovereignty switch in How to mine.

Check a single proof you didn't create. The engine exposes the verifier ladder over HTTP. What you submit is a binary FlatBuffer: a ValidationRequest (validation.fbs) that wraps the block's proof (proof.fbs) with its chain context. The /json variants take it as a base64-encoded proof_b64 field (there are raw application/octet-stream endpoints too). Submit it, then read the verdict — or look a proof up by id:

# Base64-encode the ValidationRequest and submit it to the full check:
PROOF_B64=$(base64 -i request.bin)
curl -s http://127.0.0.1:9000/v1/verify/full/json \
  -H "Content-Type: application/json" \
  -d "{\"proof_b64\": \"$PROOF_B64\"}"

# Poll an async submission (/v1/verify/full/request/submit answers 202 at once),
# or read a proof's status by id. The public endpoint is cache-backed (no durable
# store in the OSS build), so it answers for proofs this instance has recently
# seen — others come back as "NAN":
curl -s http://127.0.0.1:9000/v1/verify/status/<hash_id>
curl -s http://127.0.0.1:9000/v1/public/status/<hash_id>

A RED verdict is the interesting one: it's what rules out a faked proof — grinding a result without doing the work, or substituting a different model. You don't have to take anyone's word that the network rejects those; you can watch your own verifier do it.

Run it as a service

Pointed outward, the same engine sits behind an HTTP gateway and answers for many consumers. The OSS reference gateway bridges HTTP to the engine:

# Both processes use local imports, so run them from the service's src/ dir,
# with the FlatBuffers schema bindings on PYTHONPATH too.
pip install -r services/verification-api/requirements.txt
export PYTHONPATH="$PWD/services/verification-api/src:$PWD/shared-utils/fb-schemas"
cd services/verification-api/src

# The engine (ZMQ in, verdict out). Quick checks run CPU-only; model/full need a GPU.
python main.py

# The HTTP gateway in front of it (bridges HTTP → the engine's ZMQ).
uvicorn extapi_stub.app:create_app --factory --host 0.0.0.0 --port 9000

In Docker, the core-validation-api stack wires the engine plus a verification-http-gateway together. The OSS gateway is deliberately simple: it has API keys and rate limiting but no request signatures, JWT auth or durable storage, so a production service puts its own hardening in front of it.

<!-- TODO(refresh): decide whether to describe the hardened verifier gateway here. -->

What it needs to answer:

  • Quick / quick-smell: CPU only — useful as a cheap pre-screen.
  • Model / full: a GPU and the model weights loaded (the stack fetches the registered model into a mounted volume). This is the compute that re-runs the forward pass.
  • Config worth knowing: VERIFY_AUTH_ENABLED (off by default), VERIFY_API_KEYS, and VERIFY_RATE_LIMIT_PER_MIN gate and meter callers; health is on /health and /v1/verify/health. In the Docker stack, set OPERATOR_API_KEY (the engine exits at startup without it when its operator interface binds beyond loopback) and, if the node talks to the engine over ZMQ, the same VALIDATOR_SHARED_SECRET on both containers.

The avenues one instance can serve

The reason "as a service" is worth it: a single verifier answers several different consumers at once. From a running instance you can serve —

  1. Delegating miners. A miner that doesn't run its own verifier has its node point VALIDATOR_BASE_URL (+ VALIDATOR_API_KEY) at you, and you check its proofs.
  2. Delegating full nodes. A full node pointed at your service over HTTP (VALIDATOR_BASE_URL) hands you the full/model check instead of running it locally — it still verifies everything else itself, but trusts you for that one claim.
  3. Other validators (compute once, serve many). The /v1/verify/*/request endpoints (and their async /request/submit forms) cache results by proof id, so a verdict you computed once can be served to everyone who asks for the same proof.
  4. Explorers and public lookups. Anyone — a block explorer, a miner checking their own share — can read a proof's verdict with the public, no-auth GET /v1/public/status/{hash_id}.
  5. Operators. A separate review interface lets an operator approve or reject the model checks and challenges that land in pending review. It's served by the engine itself (/v1/operator/reviews, port 9090, loopback by default).

Run as a service responsibly: it's a convenience that centralises trust for everyone who delegates to it. That's exactly why the for-yourself path exists — a delegating miner or node can always stop trusting your service and run its own verifier instead. It's the same open-source engine, so there's nothing new to learn; the work is real, though — they have to stand the engine up on their own hardware (GPU + model) and point the node at it, as How to run a node walks through.

The other side of mining

If you read How to mine, this is the piece on the far end of the sovereignty switch. A delegated miner says "someone else checks my proofs" by pointing VALIDATOR_BASE_URL somewhere. A verification-as-a-service operator is that someone. Mining and verification are two ends of one pipeline; running the verifier is choosing which end you're on.

Where to go next

The verifier doesn't take our word for it. Run your own — for yourself or for a crowd — and neither will you.