Kỹ thuật · 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 yourself | As a service | |
|---|---|---|
| Who it serves | you — your node, your proofs | many consumers at once |
| Why | trust nobody for "the model ran" | "compute once, serve many" |
| Shape | the engine co-located with your node | the engine behind an HTTP gateway |
| Reach | one box, inward | miners, 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.
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, andVERIFY_RATE_LIMIT_PER_MINgate and meter callers; health is on/healthand/v1/verify/health. In the Docker stack, setOPERATOR_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 sameVALIDATOR_SHARED_SECRETon 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 —
- 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. - 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. - Other validators (compute once, serve many). The
/v1/verify/*/requestendpoints (and their async/request/submitforms) cache results by proof id, so a verdict you computed once can be served to everyone who asks for the same proof. - 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}. - 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, port9090, 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 OSS verifier API — every endpoint: /docs/verifier/api/
- Proof & FlatBuffers schemas — /docs/schemas/
- Run a node to validate against — How to run a node
- Mine on the same proofs — How to mine
- Why faking is expensive — the Verification whitepaper
The verifier doesn't take our word for it. Run your own — for yourself or for a crowd — and neither will you.