How it works
Dendra in five minutes
One AI request, from your prompt to the payment: client, relay, miner, chain, jury, payment.
Each step says what happens and names the file or symbol that does it, so you can check it in the open-source code. The note above the steps maps the file names to the public repository.
From prompt to payment
Six steps. The drawing and the list follow the same order.
Where the files are. In the public repository, services/gateway.py, services/client.py, services/relay.py and services/miner.py hold the files named below dendra_gateway.py, dendra_client.py, relay_server.py and miner_daemon.py. The other Python files keep their names under services/ (modea/miner.py is services/modea/miner.py), and the Go files are under chain/x/jobs/keeper.
Client: opens the job and seals the prompt
You send a prompt to the gateway, which serves the chat-completions API. The gateway acts as the client on chain: it opens a job and puts the fee in escrow, reads which miner the chain assigned to it, takes that miner's encryption key from the chain, and seals the prompt to that key.
In the code:
dendra_gateway.py::run_dendra,dendra_client.py::submit_job, and the chain's draw of the assigned miner,committee.go::deriveCommitteeOrdered.Relay: a mailbox for sealed messages
The sealed prompt is deposited at the relay, under the job and the miner it is for. The relay keeps it on disk and holds no key that opens it. Later the sealed answer waits there for the client. A miner lists only the keys that end with its own id.
In the code: the
/req,/resand/listroutes ofrelay_server.py, andrelay_client.py::listing.Miner: decrypts, answers, commits
The assigned miner finds the request, decrypts it in locked memory and runs an open model on its own hardware. It deposits the sealed answer at the relay, then anchors a commit on chain: a commitment to the question and an embedding of the answer, not their text.
In the code:
miner_daemon.py::main(its job loop),modea/miner.py::Miner.handle_job.Chain: records the commit, holds the fee
The client sends one settle transaction. When
verification_modeis 1 (optimistic), a single miner answers: the chain checks that its commit exists, holds backhold_bpsof the miner's share until finality (in basis points, so 10000 holds all of it) and pays the rest at once. The protocol cut stays in the module until finality too, and so does the burn whenhold_bpsis above zero. Whenverification_modeis 0, a committee of miners answers each job (its size iswork_committee_size) and the chain compares their answers instead.In the code:
msg_server_commit.go::CreateCommit,msg_server_settle_semantic.go::SettleSemanticandsettleOptimistic.Jury: a random sample is checked
After settlement, the random seed of a later block decides whether the job is audited (
audit_sample_bps). If it is, the chain seats a jury of other present miners, never the audited one. A juror that runs a judge opens the audited miner's sealed reveal, computes its own answer to the same prompt, compares the two and posts a verdict on chain. Only a miner started with its judge on posts verdicts, so a seat without a judge stays silent. A conviction needs three things together: enough jurors voting (audit_min_quorum), at least that many, or two thirds of the seats if that is larger, voting invalid, and a majority of the voting stake.In the code:
audit_sampling.go::runOptimisticAudit,audit_committee.go::drawAuditCommittee,antievasion.go::auditRelativeBar, and the judge side injudge_worker.py.Planned, not described above. Consensus epoch 15 makes jurors declared judges: a miner would declare its judge on chain, and only declared judges would be drawn. This step describes the chain before that upgrade, where any registered, present miner can be drawn onto a jury. It changes when the upgrade is applied.
Payment: released, or refunded
Not drawn, or upheld by the jury: the held share is released at finality and the miner is paid. Convicted: the miner loses part of its bond (
slash_leak_bps) and the client is refunded. Too few jurors, or no verdict: the chain waits. Whenaudit_unwind_blocksis above zero and the held share is older than that many blocks, the held share is refunded to the client and nobody is slashed. At finality the protocol cut also goes to the validators, the team and the treasury (protocol_fee_bps,validator_reward_bps,team_fee_bps), and the burn is applied (fee_burn_bps).On top of the fee, the Final Testnet Season pays testnet DNDR once a week, by a published formula, for verified work, juror verdicts, proven presence (on a day the identity also served a verified request) and, from a day the season announces, an active judge.
In the code:
antievasion.go::releaseHeld,audit_unwind.go::unwindStrandedRetention,final_season_payout.py,final_season_rules.py.
Who can read the prompt
The gateway, the miner that answers and, when the job is audited, the jurors who receive the reveal. The relay and the chain cannot: the relay stores ciphertext, and the chain stores a commitment and an embedding. The roadmap lists what is planned to change.
Read the settings
The numbers behind these steps are parameters of the chain, so this page names them and never quotes them.
$ curl -s https://testnet-api.dendranetwork.com/rest/dendra/jobs/v1/params
A field missing from that output holds zero. For some, audit_min_quorum among them, zero selects a default compiled into the chain, not "no floor". The fee split, the hold and the audit rate are all there. For the same steps with their diagrams, see After the answer in the docs.
Take part
Pick the part of the path you want to run or use.
Start
Two questions, then the page and the commands for your machine.
Pick your path
Run a miner or a judge
Steps 3 and 5: answer requests, and judge a sample of other miners' answers.
Open the miner guide
Run a node or a validator
Step 4: follow the chain and check every block yourself.
Open the node guide
Send a request
Step 1: any chat-completions client works, only the base URL changes.
Call the API