Call it, check it, run it.

Dendra is a public testnet. Miners, community GPUs and CPUs, answer AI requests through a chat-completions API (/v1/chat/completions). Other miners re-check a random sample of answers, and a miner convicted of cheating loses part of the stake (bond) it locked on chain. Terms are defined in the glossary.

How it works

You send a prompt to the Dendra gateway, the server behind the API. The gateway opens a job on chain and pays its fee, in DNDR, the network's token, from a testnet account it holds. A miner answers with an open model sized to its hardware. The chain holds the fee while the answer is settled (recorded on chain) and, if the job is drawn at random for audit, checked.

Request path: your prompt goes over HTTPS to the Dendra gateway, which reads it, runs the content filter and encrypts it to a miner; the miner decrypts it in memory and answers with an open model; the answer comes back the same way; the chain holds the fee, a hash of the prompt and an embedding of the answer, never the prompt itself. You browser or app prompt over HTTPS answer Dendra gateway reads the prompt runs the content filter encrypts it to the miner encrypted, via the relay answer Miner decrypts it in memory runs an open model fee hash + embedding Chain holds the fee, a hash of the prompt and an embedding of the answer; never the prompt itself Request path: your prompt goes over HTTPS to the Dendra gateway, which reads it, runs the content filter and encrypts it to a miner; the miner decrypts it in memory and answers with an open model; the answer comes back the same way; the chain holds the fee, a hash of the prompt and an embedding of the answer, never the prompt itself. You browser or app prompt over HTTPS answer Dendra gateway reads the prompt runs the content filter encrypts it to the miner encrypted, via the relay answer Miner decrypts it in memory runs an open model fee hash + embedding Chain holds the fee, a hash of the prompt and the answer's embedding; never the prompt
  1. You send a prompt over HTTPS to the Dendra gateway.
  2. The gateway reads the prompt, runs the content filter and encrypts it to the serving miner.
  3. The encrypted prompt travels via the relay to a miner.
  4. The miner decrypts it in memory and answers with an open model.
  5. The answer comes back the same way.
  6. The chain holds the fee, a hash of the prompt and an embedding of the answer, never the prompt.

Miners are not validators. Miners answer requests; validators order blocks. Owning a GPU never secures consensus.

Validators order the blocks. They finalise the chain with CometBFT consensus. Read the set on the Explorer, or with curl -s http://testnet-api.dendranetwork.com:26657/validators.

Call the API

Dendra serves the chat-completions API (/v1/chat/completions), so no custom SDK is needed. Any chat-completions client works: only base_url changes.

Base URLKeyWhat you get
https://testnet-api.dendranetwork.com/demo/v1none200. The keyless demo tier, rate-limited.
https://testnet-api.dendranetwork.com/v1required401 {"error": "unauthorized"} without a key; to call without one, use the demo base URL.
Anything that answers HTML—You reached the website. dendranetwork.com serves pages, not the API.
Pythonkeyless demo tier
# Python, with a chat-completions client package (pip install openai)
from openai import OpenAI
client = OpenAI(base_url="https://testnet-api.dendranetwork.com/demo/v1", api_key="unused")

r = client.chat.completions.create(
    model="dendra-network",
    messages=[{"role": "user", "content": "Capital of Australia?"}],
)
print(r.choices[0].message.content)
curldemo tier, then keyed tier
# curl, keyless demo tier
curl -s https://testnet-api.dendranetwork.com/demo/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"dendra-network","messages":[{"role":"user","content":"Capital of Australia?"}]}'

# keyed tier: same body, plus the bearer token
curl -s https://testnet-api.dendranetwork.com/v1/chat/completions \
  -H "Authorization: Bearer YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"model":"dendra-network","messages":[{"role":"user","content":"Capital of Australia?"}]}'

Set a generous timeout, in minutes rather than seconds. One consumer GPU serves each answer, and requests queue. Latency depends on the capacity online when you call: /capacity lists the hardware operators declare.

The dendra block

A response that a miner served carries one extra block. When streaming, it arrives in the last chunk. No dendra block means no miner served the job: handle that case instead of raising on it.

dendra blockcomments added
"dendra": {
  "job_id": "job_…",             // the job's id on chain
  "miner_id": "dm1…",            // the miner that answered; null when several did
  "committee": ["dm1…"],         // assigned to serve the job, not the audit jury
  "beacon": "…",                 // public random seed (VRF) that picked the miner
  "settled": true,               // false: settlement refused, the answer is unverified
  "audit_state": "pending",      // always "pending" here: the audit comes later
  "cost_udndr": …,               // settled cost · 1 DNDR = 1,000,000 udndr
  "escrow_udndr": …,             // the amount held for the job
  "verify": {                    // for checking later (dendrad: see the glossary)
    "proof_endpoint": "/proof",  // resolve against https://testnet-proof.dendranetwork.com
    "query": "dendrad query jobs get-job job_…"
  }
}

After the answer

Every answer settles on chain, but settled is not verified: a random sample of jobs is audited afterwards.

Life of a fee, with its parameters: the fee is held at settlement (hold_bps); a later block's random seed draws whether the job is audited (audit_sample_bps); if not drawn, it is released at finality and the miner is paid; if drawn, a jury of other miners judges the answer (the jury excludes the audited miner), with a floor of audit_min_quorum + 1 present, eligible miners: upheld, the miner is paid; convicted, the miner is slashed (slash_leak_bps) and the client refunded; with too few jurors, a deferred draw, or no verdict within audit_unwind_blocks, the client is refunded and nobody is slashed. hold_bps Held at settlement the client's payment waits for the draw audit_sample_bps A later block draws is this job audited? from that block's random seed not drawn Released at finality the miner is paid drawn A jury of other miners judges the answer; the jury excludes the audited miner. Floor: audit_min_quorum + 1 present, eligible miners Upheld the miner is paid slash_leak_bps Convicted the miner is slashed, the client is refunded audit_unwind_blocks No verdict too few jurors, draw deferred, or out of time: client refunded, nobody is slashed Life of a fee, with its parameters: the fee is held at settlement (hold_bps); a later block's random seed draws whether the job is audited (audit_sample_bps); if not drawn, it is released at finality and the miner is paid; if drawn, a jury of other miners judges the answer (the jury excludes the audited miner), with a floor of audit_min_quorum + 1 present, eligible miners: upheld, the miner is paid; convicted, the miner is slashed (slash_leak_bps) and the client refunded; with too few jurors, a deferred draw, or no verdict within audit_unwind_blocks, the client is refunded and nobody is slashed. hold_bps Held at settlement the client's payment waits for the draw audit_sample_bps A later block draws is this job audited? from that block's random seed not drawn Released at finality the miner is paid drawn A jury of other miners judges the answer; the jury excludes the audited miner. Floor: audit_min_quorum + 1 present, eligible miners Upheld the miner is paid slash_leak_bps Convicted the miner is slashed, the client is refunded audit_unwind_blocks No verdict too few jurors, draw deferred, or out of time: client refunded, nobody is slashed
  1. Held at settlement (hold_bps).
  2. A later block's random seed draws whether the job is audited (audit_sample_bps).
  3. Not drawn: released at finality, the miner is paid.
  4. Drawn: a jury of other miners, seated from present, eligible miners with the audited one excluded; the floor is audit_min_quorum + 1.
  5. Upheld: the miner is paid. Convicted: the miner is slashed (slash_leak_bps) and the client refunded.
  6. Too few jurors, a deferred draw, or no verdict within audit_unwind_blocks: the client is refunded and nobody is slashed.

Not drawn, the job is paid at finality (the release of the held fee) with no verdict. The deterrent is that a miner cannot know in advance which jobs will be drawn; the seed comes from the validators' verifiable random function (VRF) while committee_seed_source is 1, after the miner has committed its answer.

To convict, "invalid" verdicts must come from at least two thirds of the anchored seats, rounded up (jury seats drawn and recorded on chain before anyone votes), and never from fewer than audit_min_quorum jurors; the larger of the two is the bar (antievasion.go::auditRelativeBar). They must also come from a strict majority of the voting stake (the bonds of the jurors who voted). The miner is slashed, losing part of its bond, and the client refunded.

No verdict, no slash. When no verdict comes within audit_unwind_blocks, the held fee goes back to the client and nobody is slashed. That happens below the jury floor (audit_min_quorum + 1 present, eligible miners), when the jurors are silent or split, or when the draw stays deferred for lack of randomness. A drawn job's held fee is paid only if its jury, or a governance vote, upholds the answer.

At finality, at genesis values (governable), each 100 DNDR of fee pays 80 to the miner, 7.5 to validators, 4.5 to the treasury and 3 to the team; 5 are burned. A refund burns nothing. A paid job also opens a work subsidy, a reward from the Reserve (DNDR set aside at genesis) that the miner software claims.

Parameters you can read. Shares are in basis points (bps): 10000 = 100 %. hold_bps: share held at settlement. audit_sample_bps: share of jobs drawn. audit_min_quorum: floor of the jury bar; a verdict needs the larger of it and two thirds of the anchored seats. audit_unwind_blocks: blocks before an unresolved job is refunded. slash_leak_bps: share of stake a conviction takes. min_stake: smallest miner bond, in udndr. The fee split is there too. Read them live, never from this page:
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”. silence_slash_bps has no effect: the only code that reads it, antievasion.go::clawbackPayment, is not called anywhere in production, so nothing is taken for silence by this parameter.

Check an answer

The audit lands after the answer, so check later. Look for your job_id in the recent_audits of the public audit feed, https://testnet-proof.dendranetwork.com/proof, shown live on the home page and read by the Explorer, or read the job straight from the chain:

Read a jobcurl
curl -s https://testnet-api.dendranetwork.com/rest/dendra/jobs/v1/job/<job_id>

Its state field carries the same markers as the audit feed. On a node, verify.query is the same read with dendrad. "Verified" means a jury audited the answer and upheld it. A state can carry several markers at once: read them in the table's order.

What you findMeaningWhat to do
Not in the feedNot drawn, outside the feed's window, or its draw deferred.Read the job; unwound there means refunded.
unwoundRefunded: no jury concluded in time. Nothing was verified.Treat the answer as unverified; the fee went back to the client.
clawedRejected: the miner was slashed and the client refunded.Do not act on the answer.
vindicatedAudited and upheld by the jury. The strongest state.Rely on the audit.
resolvedClosed another way: a re-hearing (the state also carries adjudicated), a governance vote, or a challenge no jury ruled on.Read the job. A slash_records entry for its miner_id means it was convicted: do not act on the answer. adjudicated with no entry means its jury upheld it. Otherwise, treat it as unverified.
None of theseThe audit is still running.Read again later.
Pythonclassify a job's audit
import json
import urllib.request

CHAIN = "https://testnet-api.dendranetwork.com/rest/dendra/jobs/v1"


def audit_outcome(state):
    """How the chain says an audit ended. Markers are whole words: noquorum is not quorum."""
    marks = set(state.split("+"))
    if "clawed" in marks:
        return "convicted"       # a jury convicted the miner and the client was refunded: do not act on the answer
    if "resolved" not in marks:
        return "no_verdict_yet"  # not drawn, waiting for a jury, or still open: most jobs stay here
    if "unwound" in marks:
        return "refunded"        # no jury ruled and the fee went back to the client: nothing was verified
    if {"vindicated", "quorum"} <= marks:
        return "upheld"          # a jury at the bar upheld the answer: that jury's verdict, not a proof
    return "unclear"             # a re-hearing, a governance vote, a challenge no jury ruled on, or an older state: read the job


meta = resp.model_extra["dendra"]    # the client package keeps extra fields here
job = json.load(urllib.request.urlopen(CHAIN + "/job/" + meta["job_id"]))["job"]
outcome = audit_outcome(job["state"])

What is checked, and what is not

Verification here comes in tiers, and each tier says what it can see and what it cannot. Nothing below is a count or a state typed into this page: whether a check is switched on is a reading, and the table at the end of the section reads it live.

Tier 1: a jury checks a sample of answers

A random draw (audit_sample_bps) selects settled jobs. A jury of other present miners, with the audited miner excluded, re-reads the answer and votes. A verdict needs votes the same way at the jury bar, the larger of audit_min_quorum and two thirds of the anchored seats, rounded up (antievasion.go::auditRelativeBar), and a strict majority of the voting stake. A conviction slashes part of the stake and refunds the client; an upheld answer releases the held fee.

What this tier does not see: a job the draw does not select is checked by nobody. A juror judges with a model, so a verdict is an opinion of that model, not a recomputation. A drawn job whose jury does not reach the bar is refunded to its client after audit_unwind_blocks, and nothing was verified.

Tier 2: checks that are built and wait on a parameter

  • The availability challenge. Armed, every avail_epoch_blocks blocks each bonded miner must post a VRF proof over that window's challenge, which is the AppHash of the window boundary, before avail_deadline_blocks have passed (msg_server_prove_availability.go::ProveAvailability). An absence counts as one failure. A miner with avail_fail_k failures within a sliding window of avail_fail_window windows is slashed, by a bounded share of its stake (avail_slash_bps, capped by avail_slash_max) that is burned (availability.go::runAvailabilitySlash). It checks that a bonded miner is online and holds its key. It does not check that any inference was done, and it does not check that an ordinary job was computed honestly. The slash is dormant while avail_slash_bps, avail_fail_k or avail_fail_window is 0. avail_threshold_bps is read by no consensus code.
  • The model registry. With enforce_model_registry on, a commit must name a registered, active model, and when the registry holds a weights hash for it, the hash in the commit must match (msg_server_commit.go::CreateCommit). It compares what the miner writes against the registry. It cannot see which weights ran.

Presence proofs are separate from both: each window a miner proves it is online with a VRF proof, and only present miners are drawn for work or audit. A proof of presence says a key answered, not that any inference was done well.

Tier 3: nothing checks it yet

  • A judge is a signed byte. The chain checks who signed a verdict commit and nothing about an inference (msg_server_commit.go::CreateCommit); the tally reads one value as the accusation and any other as a vindication (antievasion.go::auditVerdictTally). A judge that read the answer and a judge that posted a byte look the same on chain.
  • That a model ran. Miners can sign a fingerprint of their client code and model weights, and the relay can require it for confidential jobs (DENDRA_ATTEST_REQUIRE). The shipped docker-compose.yml does not set that variable for the relay, so no miner is required to present one: the attestation gate is dormant. Armed, it would check a signed statement, not the machine.
  • What a report declares. The hardware, the judge role and the kit version in a capacity report are what the operator writes, signed or not.
  • Hardware-sealed tiers. Enclave hardware and secret-sharing across miners are on the roadmap. No job is verified or sealed that way.

Read it live

reading the chain

ParameterReadsMeaning
audit_sample_bps...Share of settled jobs drawn for a jury, in basis points (10000 = 100 %).
audit_min_quorum...Floor of the jury bar. At 0 the chain uses the compiled floor of 4.
audit_unwind_blocks...Blocks after which an audit with no verdict is refunded; 0 turns the refund off.
avail_epoch_blocks...Length of the availability window in blocks; 0 turns the online check off.
Availability challenge...Armed only when avail_epoch_blocks, avail_slash_bps, avail_fail_window and avail_fail_k are all above 0, the four the slash function reads (availability.go::runAvailabilitySlash). The parameter check also requires avail_deadline_blocks above 0 once avail_slash_bps is.
enforce_model_registry...Whether a commit must name a registered, active model.
audit_judge_model...The model the kit judge reads to choose what it runs. No consensus code reads it: the chain does not constrain which model a judge runs.

“Unavailable” marks a failed read, not a zero. A field missing from the chain's answer holds zero, because the chain omits zero values. Read the same fields yourself with curl -s https://testnet-api.dendranetwork.com/rest/dendra/jobs/v1/params and curl -s https://testnet-api.dendranetwork.com/rest/dendra/modelregistry/v1/params.

Pick a role

Each role runs different software and risks different things. Pick one before installing. Join with a GPU or with a CPU: a GPU (NVIDIA) mines, and a CPU with enough RAM judges, for now, and serves its share too; a full node or a validator needs no GPU.

Miner

Answers requests with a local open model, paid from their fees.

Needs an NVIDIA GPU to mine with a model sized to the card: the hardware probe picks it. For a machine without a GPU, kit v0.2.2 keeps the rule that kit v0.2.1 set: it joins only as a judge (next box, and the rule below). Risks its bond, if a jury convicts a drawn answer.

Judge

A miner run with --judge: it also votes when drawn onto a jury, which lets audits conclude. The chain draws jurors among all present miners, so a miner without an active judge is drawn all the same, and its seat casts no vote: a silent seat. A juror is a registered miner, so a judge also serves requests, on its GPU if it has one.

Needs at least MOE_CPU_MIN_RAM_MB of system RAM, the kit's judge floor (the report of bash deploy/hw_probe.sh prints it, and from kit v0.2.1 bash deploy/hw_probe.sh --judge-floor-mb prints it alone), with or without a GPU: the judge runs on the CPU, with the model the kit reads from the model registry (audit_judge_model, which no consensus code enforces), a mixture-of-experts. Under Windows, that is the RAM of WSL 2, about half of the PC's by default; the memory= line of the [wsl2] section of %UserProfile%\.wslconfig raises it. The installers take this role by default and refuse it under 32 GB of free disk: pass --miner (-Miner on Windows) to install a miner only. The probe in Run a miner, step 1, decides. Risks the same bond.

Validator

Orders blocks and adds to the draw's randomness; answers no requests.

Needs an always-on server (a VPS), no GPU, and port 26656 reachable: bash deploy/node_reachability.sh checks it. Risks its bond: long downtime gets it jailed (dropped from block production) and slashed.

How: an installer with --validator (-Validator on Windows), or the by-hand join.sh command of Run a miner, step 3, with --validator in place of --judge. Step by step: node and validator.

Full node

Follows the chain and serves RPC and REST. Signs nothing.

Needs no GPU. Risks nothing, earns nothing.

How: deploy/testnet-node/ in the repository.

Kits v0.2.1 and v0.2.2, for machines without a GPU. A machine with no GPU joins only as a judge: it needs at least MOE_CPU_MIN_RAM_MB of system RAM, and it answers the requests drawn for it with the judge's model, not with a mining model. With no GPU and less RAM, those kits refuse to join, and leave untouched a miner an earlier kit installed. From the instant KIT_DEADLINE names (read it with curl -sf https://testnet-api.dendranetwork.com/network-info.txt), the relay refuses a kit below KIT_MIN, and from the season day that kit_rules_from_day names (curl -s https://testnet-api.dendranetwork.com/final-season/v1/status) the season pays it nothing. Such a machine leaves the network with deploy/testnet-miner/exit-miner.sh (bash deploy/testnet-miner/exit-miner.sh --help prints the steps). The chain cannot see the hardware: a miner of an earlier kit keeps running and keeps being drawn, and as a juror it votes nothing.

More roles and technologies for CPU-only machines are planned.

Stake and the work draw

Every miner locks a stake (bond) of at least min_stake to take work. The chain draws who serves each request among present miners, weighting each identity by its stake up to a ceiling of assignment_stake_cap_multiple × min_stake (committee.go::capAssignmentWeights). At a multiple of 1, a stake above min_stake buys no more work. Governance sets the multiple: proposal 1 on this testnet proposes 1, and its status is read with curl -s https://testnet-api.dendranetwork.com/rest/cosmos/gov/v1/proposals/1. Read the value in force rather than this page:

Read the values in forcecurl
curl -s https://testnet-api.dendranetwork.com/rest/dendra/jobs/v1/params
# assignment_stake_cap_multiple, min_stake; a field missing from the output holds zero:
# a multiple of 0 selects the compiled 2, a min_stake of 0 sets no ceiling

The faucet's drip size is the amount in its status (step 2), next to amount_source, where it comes from. The faucet code of kit v0.2.1 can read it from the chain's min_stake (DENDRA_FAUCET_AMOUNT=min_stake), so that one drip bonds one identity. The audit jury is drawn by stake too, and that draw does not read the ceiling (audit_committee.go::drawMembersWithDomain). A stake earns no Final Testnet Season reward by itself.

Run a miner

Four steps, one of them optional, take a machine from nothing to serving requests.

Step by step, one page each: miner and judge, node and validator, and update an installed kit.
Run a miner in four steps. 1 Check: hw_probe.sh decides what your machine can serve. 2 Wallet, optional: an address for your rewards; the miner funds its own key from the faucet. 3 Install: install.sh (Ubuntu, Debian, HiveOS), install.ps1 (Windows, via WSL 2) or join.sh by hand from a clone; both scripts hand over to join.sh, and on a desktop session install.sh also adds the Dendra app. 4 Serve: bond at least min_stake and answer jobs; with --judge, which the installers pass, the node also posts a verdict when it is drawn onto a jury, if the probe allows it. The miner only opens outbound connections to the relay, the chain and the faucet; no inbound port is needed. 1 Check hw_probe.sh decides what your machine can serve 2 Wallet optional: an address for your rewards the miner funds its own key 3 Install install.sh Ubuntu, Debian, HiveOS install.ps1 Windows, via WSL 2 join.sh by hand, from a clone both scripts hand over to join.sh; on a desktop, install.sh adds the app 4 Serve bond ≥ min_stake, then answer jobs --judge: votes when drawn, if the probe allows it Your miner behind a home router is fine outbound connections only no inbound port to open Dendra network relay, chain, faucet Run a miner in four steps. 1 Check: hw_probe.sh decides what your machine can serve. 2 Wallet, optional: an address for your rewards; the miner funds its own key from the faucet. 3 Install: install.sh (Ubuntu, Debian, HiveOS), install.ps1 (Windows, via WSL 2) or join.sh by hand from a clone; both scripts hand over to join.sh, and on a desktop session install.sh also adds the Dendra app. 4 Serve: bond at least min_stake and answer jobs; with --judge, which the installers pass, the node also posts a verdict when it is drawn onto a jury, if the probe allows it. The miner only opens outbound connections to the relay, the chain and the faucet; no inbound port is needed. 1 Check hw_probe.sh decides what your machine can serve 2 Wallet optional: an address for your rewards the miner funds its own key 3 Install install.sh Ubuntu, Debian, HiveOS install.ps1 Windows, via WSL 2 join.sh by hand, from a clone both scripts hand over to join.sh; on a desktop, install.sh adds the app 4 Serve bond ≥ min_stake, then answer jobs --judge: votes when drawn, if the probe allows it Your miner behind a home router outbound only no inbound port Network relay, chain, faucet
  1. Check: hw_probe.sh decides what your machine can serve.
  2. Wallet, optional: an address for your rewards; the miner funds its own key from the faucet.
  3. Install: install.sh on Ubuntu, Debian or HiveOS; install.ps1 on Windows, via WSL 2; or join.sh by hand from a clone. Both scripts hand over to join.sh; install.sh adds the desktop app.
  4. Serve: bond at least min_stake, then answer jobs; with --judge, which the installers pass, the node also posts a verdict when it is drawn onto a jury, if the probe allows it.
  5. Your miner only opens outbound connections, to the relay, the chain and the faucet: no inbound port to open, and a miner behind a home router (NAT) is fine.
  1. Check your machine

    The probe decides what your machine can serve, and the installers run it for you. To see its answer first on Linux, clone the repository and run it: it prints a role line, mine only or mine + judge. On Windows, skip this step: install.ps1 runs the probe once WSL, the Linux layer it installs on Windows, is ready.

    Linuxcheck what the machine can serve
    git clone https://github.com/DendraNetwork/dendra-network.git && cd dendra-network
    bash deploy/hw_probe.sh
  2. Optional: a wallet for your rewards

    You need no wallet to mine. When it starts, the miner creates its own key and funds it from the public faucet, a service that hands out testnet DNDR. Job pay goes to that key. Final Testnet Season rewards go there too, unless you declare another address, such as one made on the wallet page (how: Final Testnet Season). Your wallet balance is not your season reward: only what the season pays counts (what counts).

    A wallet that only receives rewards needs no funds. If you fund one anyway, the faucet's limits apply per address, per IP and overall; 429 means one is reached (which one, and what to do).

    Use a dedicated testnet wallet. Never reuse a recovery phrase that controls real funds.
    Fund a wallet by hand: the proof-of-work claim

    Ask the faucet first: its reply gives the drip size and the difficulty of a small proof of work, a hash puzzle that slows abuse. After a claim, check the credit in the wallet.

    Faucet claimcurl, then Python
    # difficulty and drip size, straight from the faucet
    curl -s http://testnet-api.dendranetwork.com:4500/
    # prints {"status": "ok", "from": "...", "amount": "...", "pow_bits": ...}
    
    # mine the nonce, then claim
    python3 - <<'EOF'
    import hashlib, itertools, json, urllib.request
    ADDR, BITS = "dendra1...", 20  # BITS = pow_bits reported above
    for n in itertools.count():
        h = hashlib.sha256(("%s:%d" % (ADDR, n)).encode()).digest()
        if int.from_bytes(h, "big") >> (256 - BITS) == 0: break
    req = urllib.request.Request("http://testnet-api.dendranetwork.com:4500/",
        json.dumps({"address": ADDR, "pow": str(n)}).encode(),
        {"Content-Type": "application/json"})
    print(urllib.request.urlopen(req).read().decode())
    EOF
  3. Install

    Pick one path. Each ends in deploy/join.sh, which joins the network. Download, read, run: take the script from the repository and read it first. The installers change nothing until you pass --yes (-Yes in PowerShell). There is no curl … | sh: it would run bytes you never saw.

    Ubuntu, Debian, HiveOS. deploy/install.sh installs Docker, and the NVIDIA container toolkit when a GPU is present, clones the repository, then runs join.sh. On a desktop session it adds the Dendra app, which shows your recovery phrase and earnings.

    Ubuntu, Debian, HiveOSinstall.sh
    bash install.sh        # plan only, changes nothing
    bash install.sh --yes  # install, then join

    Windows. deploy/install.ps1 installs WSL 2 and Ubuntu, then runs install.sh inside it. Run it from an administrator PowerShell, in the folder that holds it. It stops for a restart, then for Ubuntu's first launch: run it again each time.

    Windowsinstall.ps1, administrator PowerShell
    powershell -ExecutionPolicy Bypass -File .\install.ps1     # plan only
    powershell -ExecutionPolicy Bypass -File .\install.ps1 -Yes

    By hand. Read the script in your clone (quit the pager with q), then run it.

    By handjoin.sh, from your clone
    less deploy/join.sh
    CONFIG_URL=https://testnet-api.dendranetwork.com/network-info.txt bash deploy/join.sh --judge

    The genesis check. join.sh checks the genesis it downloads against the GENESIS_SHA256 line of network-info.txt and against docker/GENESIS_SHA256 in your clone, and stops on a mismatch. By hand: curl -s https://testnet-api.dendranetwork.com/genesis.json | sha256sum, then compare it with both. This page prints no digest, since a reset changes it: compare against the two sources above.

  4. Serve

    The miner registers and bonds by itself: by default min_stake, read from the chain (parameters).

    Success looks like [OK] miner alive and registered at the end of join.sh. Follow it from your clone (~/dendra-network when an installer made it; on Windows, inside Ubuntu): docker compose -f deploy/testnet-miner/docker-compose.yml logs -f miner. "Waiting for jobs" is normal.

    Back up your identity. The Docker volume dendra-miner_miner-keys holds your miner's key: delete it and you need a new bond. How to back it up and encrypt it: Back up and encrypt your keys. To leave the network: Leave and get the stake back.

    Judge too. The installers pass --judge, as does the command above: join.sh then judges if the probe allows it, and only mines otherwise. The judge runs on the CPU, whether or not the machine has a GPU: the probe allows it from MOE_CPU_MIN_RAM_MB of system RAM (bash deploy/hw_probe.sh --judge-floor-mb prints it).

Operate your miner

Tasks for a miner that is already running. Run them from your clone (~/dendra-network when an installer made it; on Windows, inside Ubuntu). The exit and the key encryption print what they would do and change nothing until you add --yes.

Leave the network and get the stake back

exit-miner.sh deregisters the miner on chain (delete-miner). The chain returns the remaining stake to the key that registered the miner, minus anything slashed earlier. Run it once without a flag: it reads your miner and the chain, asks the chain whether it would accept the exit, and changes nothing.

Leave the networkfrom your clone
bash deploy/testnet-miner/exit-miner.sh                # read and simulate, changes nothing
bash deploy/testnet-miner/exit-miner.sh --yes          # drain, then leave if the chain accepts
bash deploy/testnet-miner/exit-miner.sh --yes --wait   # keep asking until the chain accepts

With --yes the script first sets the drain: the miner takes no new work and no new jury seat, and it still files the reveals for its own audited jobs. Keep a draining miner running.

The chain refuses while the miner holds an obligation: a fee held on a job it served, a seat on an audit that has not resolved yet, a job under dispute, or an answer that is not settled. The script prints the chain's own message and lists what it can read of what holds the miner. A refusal is a reading to repeat later, not a failure, and --wait repeats it for you.

After the exit the miner stays stopped. Starting it again registers it again and stakes again. To take the kit off the machine, run bash deploy/uninstall.sh: it keeps the miner's keys unless you pass --delete-keys, and it makes a verified backup of them before it removes anything.

Owner mode. When the stake sits on an owner key that is not on this machine (below), the script never signs with this machine's key. With --yes it prepares delete-miner.json next to the script and prints the command that signs it offline, on the owner's machine. A second run with --yes --signed delete-miner.signed.json checks the file, sends it and reads the chain back.

Several cards. With one identity per card (below), --slot <k> names the identity that leaves. On such a machine --yes without --slot is refused, because an exit is never taken on slot 0 by default.

Back up and encrypt your keys

The miner's identity is its key: the chain derives the miner id from the key's address, so a lost key is a lost identity, with its stake. The keys live in the Docker volume dendra-miner_miner-keys: the key that signs and holds the stake, the encryption key, the VRF key and the attestation key. Never run docker compose down -v or docker volume prune on a machine that holds it.

  • New installs are encrypted. join.sh creates a random passphrase file, ~/.config/dendra/miner-secrets/keyring-passphrase (directory and file readable by you only), outside the volume and outside the clone. --plain-keys keeps a new install unencrypted, on purpose.
  • Keys that are not encrypted yet stay so until you run the migration. It keeps the same address.
  • The 24 words. The miner keeps the recovery phrase of a key it creates. The Dendra app shows it. Write it on paper: it is the only way back if the passphrase file is lost, and the migration refuses to run until you have.
  • Back up both the volume and the passphrase file, and keep the copies apart: together they are an unencrypted key. Without the passphrase an encrypted keyring does not open, and the miner stops with that reason instead of creating a new key.
Keysfrom your clone
bash deploy/testnet-miner/encrypt-keys.sh --yes          # encrypt keys that are not (run it once without --yes first)
bash deploy/testnet-miner/backup-keys.sh backup          # one encrypted archive of the volume and the passphrase file
bash deploy/testnet-miner/backup-keys.sh verify ARCHIVE  # open it again and check it

backup-keys.sh asks for a passphrase of its own, reads the archive back and compares it with the volume before it says it is written. Copy the archive off the machine. restore puts it back and never writes over a key; restore before the miner first starts on a new system, since a miner that starts on an empty volume creates a new identity.

Encryption protects the volume and every backup of it. It does not protect a machine that is compromised while the miner runs: the passphrase sits on the same machine, so that the miner restarts without you.

Where rewards go: payout address and owner mode

Without a declaration, rewards go to this machine's own key, which anyone who copies the machine's keys can spend. Declare an address whose key is not on this machine, such as one made on the wallet page.

Payout addressat install, or by hand
# at install: the checksum is verified before anything changes
CONFIG_URL=https://testnet-api.dendranetwork.com/network-info.txt bash deploy/join.sh --payout-address dendra1...

# later, from deploy/testnet-miner
docker compose exec miner python3 final_season_miner.py payout --address dendra1...

The miner declares the address once it is registered, and again only when it changes. The Dendra app has the same step on its Where rewards go card. Add --payout-lock to join.sh (or --lock to the command above) and the programme holds the address for good: any other address is refused for that identity, and the lock cannot be lifted. What counts toward the season is on the Final Testnet Season page.

Owner mode is an advanced option for an operator with a second device that holds a key and runs dendrad to sign offline. join.sh --owner dendra1... puts the stake on that key:

  • The owner key creates the miner, supplies the stake, is the only key that updates or deletes the miner, and receives the stake back on exit.
  • This machine's key is the operator. It signs the commits and availability proofs, and the chain pays it.
  • The miner never sends create-miner in this mode. It writes the unsigned transaction and prints three complete commands: copy it out, sign it on the owner's device, broadcast it from this host. Read them with docker compose -p dendra-miner logs miner | grep -A16 'OWNER MODE'. The miner works once the chain records this machine's key as the operator.
  • A payout declaration in this mode is not signed by this machine: final_season_miner.py payout-prepare writes the transaction, you sign it on the owner's device, and payout-submit sends it.
  • The miner's identity derives from the owner address. A wrong owner is another identity, so check the address before you run it.

Publish your hardware

The network page shows the hardware that miners declare. join.sh schedules the publisher (publish-capacity.sh) with an hourly cron job and runs it once the registration is seen. The registry ages out a report that is not renewed, so the repetition matters: a miner that stops publishing drops off the capacity listing.

  • The report is signed, and it is sent only after the chain records this identity with the signing key as its operator. Until then nothing is sent and the next run asks again.
  • It runs on the host, not in the container, because the container has no GPU. The cron line uses bash -lc: without a login shell the probe may not find nvidia-smi (under WSL it lives in /usr/lib/wsl/lib) and would publish a smaller tier than your card.
  • The registry address comes from the node address, and only when that is a host name. On a bare IP address nothing is derived; set DENDRA_CAPACITY_URL to the registry's address.
  • The public chat does not count these reports. It counts the miners registered on chain with a presence proof the chain accepted.
Publish nowfrom your clone
bash deploy/testnet-miner/publish-capacity.sh              # every active identity of this machine
bash deploy/testnet-miner/publish-capacity.sh --slot 1     # one identity, with one identity per card
cat deploy/testnet-miner/publish-capacity.log              # what the hourly job said

Exit code 0 means published and signed. 2 means the chain records no such miner, or records it for another operator. 3 means the registration could not be read, and it is never taken as registered. 1 is a configuration or probe failure, or a refusal by the registry. If your host has no crontab, join.sh prints the command to schedule yourself.

Several cards in one machine

By default one machine is one miner identity. With --gpus, join.sh gives each NVIDIA card an identity of its own, called a slot, with its own keys, its own 24 words and its own stake. Slot 0 is the installation as it always was; the others are named dendra-miner-g1, dendra-miner-g2, and so on. Add --plan first: it prints what would start and changes nothing.

One identity per cardfrom your clone
CONFIG_URL=https://testnet-api.dendranetwork.com/network-info.txt bash deploy/join.sh --gpus all --plan
CONFIG_URL=https://testnet-api.dendranetwork.com/network-info.txt bash deploy/join.sh --gpus all
bash deploy/testnet-miner/slots.sh list                  # slot, project, state, card, miner id
  • --gpus takes all, card indices (0,2) or card UUIDs. A card that leaves the list has its slot stopped. A card that is no longer in the machine is not started and not retired: nothing is bound to another card in silence.
  • To bind an existing slot to another card on purpose: --reassign <slot>=<card index or UUID>. The identity, the stake and the keys do not move.
  • join.sh measures the free RAM before it starts each added slot, and the judge is counted once per machine.
  • Every slot but slot 0 declares itself as a secondary share of the host, so the registry counts the machine's RAM and cores once.
  • Key tools take --slot <k>: encrypt-keys.sh also takes --all, and exit-miner.sh needs it with --yes. Back up the volume of every slot: slots.sh list names them.

When docker compose up fails

join.sh ends with "docker compose up failed" when Docker refused to start a container. The reason is in the output just above that line. The usual ones:

What you seeWhat it meansWhat to do
could not select device driverThe GPU override asks Docker for an NVIDIA card, and Docker cannot give one.Run join.sh again: it removes the override when no card is usable. To mine on a card, install the NVIDIA container toolkit (install.sh does it when it sees a GPU), then check with the command join.sh prints.
The pinned image could not be pulledThe registry is down, unreachable or private.Nothing to do: join.sh builds the same image from your clone instead. It takes longer and needs free disk.
The node's preflight exits with code 78 and says Refusing to startThe node's volume already holds a chain home that this copy of the kit was not told to use, for example one left by an earlier network.Read docker compose -f deploy/testnet-node/docker-compose.yml logs preflight node; join.sh prints the last lines of it. If the home is yours, from a node you started by hand, say so once: echo 'DENDRA_ADOPT_EXISTING_HOME=1' >> deploy/testnet-node/.env, then run join.sh again. If it came from another network, do not.

A machine without Docker or the Compose v2 plugin never gets this far: join.sh stops at its pre-flight with [FAIL] Docker/Compose v2 missing, before it starts anything. Install Docker, or, on an apt-based system (Ubuntu, Debian, HiveOS), run install.sh.

Free disk matters too: the served model, the images and the chain state land under the clone and Docker's data root. If the output does not match any row, ask in #operator-support on the Discord and paste the lines above the failure.

When a request is refused

The faucet and the relay name the reason when they refuse a request, and their reply carries a help field with the address of the section here or on the update page that settles it.

The faucet's limits

The faucet protects its budget with three limits, all set by its operator: one drip per address in a cooldown, a number of drips per IP address per day, and a total for the whole faucet per day. This page prints no value, since the operator can change them. A refused request spends none of them. The reply is a 429 and its info says which one you met:

infoWhat it meansWhat to do
address funded recently (cooldown)This address got a drip within the cooldown.Wait. A miner that is registered already holds its stake, and a wallet that only receives rewards needs no funds.
too many requests from this IP (daily quota)This IP address used its drips for the day. Machines behind one home router share an IP address, and a rig asks once per identity.Wait, then run join.sh again.
global daily cap reached (anti-drain)The faucet has paid out its total for the day.Try again later. Nothing on your side is wrong.

A 403 with stale kit is not a limit: the kit is below the network's floor. Update it: two commands. A 400 with invalid kit_version means a client wrote the kit number in a form that is not a whole number; the kits write it correctly, so update the kit or fix the client.

Why the relay refused a write

A refused write gets a 401 with four fields: error, why, how and help. why starts with the reason word and ends with a detail. Your miner logs the relay's own reason once per route; read it before you suspect the token. Reading the work queue needs no token, so a refused write does not hide the jobs from a miner. A reason that starts with STALE_KIT points to the update page.

ReasonWhat it meansWhat to do
STALE_KITThe signed body declares a kit version below the network's floor, or declares none.Update the kit.
unsigned, malformed, MALFORMED, UNREADABLE_HEIGHTThe write has no signature headers, a header or the signed message cannot be read, or the signed message has no height.Update the kit. A miner started outside the kit needs a signing key (DENDRA_SIGN_KEY).
offThe relay does not check signatures (DENDRA_RELAY_SIGN=off), so it accepts only a write that carries its shared token, and this one carried none or a wrong one.Send the relay's token in X-Dendra-Token, or ask the relay's operator to arm signature checking.
INVALID_SIGNATUREThe signature does not cover this message: the body or a header changed after signing.Check that nothing between the miner and the relay rewrites requests.
KEY_MISMATCHThe key files the deposit under one miner and the header names another.Keep each identity's own keys. On a rig, each slot signs as itself.
FOREIGN_KEYThe signature is valid, but its key is not the operator the chain records for this miner.Sign with this machine's key, the one in the miner's volume.
UNKNOWN_MINERThe registry the relay read does not list this miner.Wait until the registration is on chain. The relay reads the registry again after an unknown miner. If the miner is not registered, read its log.
REGISTRY_MUTE, JOB_REGISTRY_MUTEThe relay has never read the registry or the job list, so it can attribute nothing.It is on the relay's side. Try again later, then ask in #operator-support.
REPLAYThe relay already accepted these exact bytes.Nothing, for a deposit a miner makes again at every start: the relay keeps the first copy.
HEIGHT_REGRESSION, TOO_OLD, TOO_FAR_AHEAD, UNSEALED_HEIGHTThe signed height is below the highest one accepted from this key, or, where the relay has a chain head to compare with, outside the freshness window.The next write carries a current height. If it repeats, ask in #operator-support with the log line.

A client that pays for its own request signs a req deposit, and the relay checks the job as well. Most readers never meet these reasons: the public gateway is the one that writes requests.

ReasonWhat it means
UNKNOWN_JOB, FOREIGN_CLIENTThe job is not in the list the relay read, or the key is not the account that paid for it.
PRICE_UNSET, UNDERPAIDThis relay sets no request price, so it takes no signed request, or the job escrowed less than the price.
FEE_UNREADABLE, JOB_STATE_UNREADABLE, COMMITTEE_UNREADABLEThe relay could not read the job's fee, its state or its committee from the chain.
JOB_NOT_OPENThe job no longer waits for its request: it is settled, paid, expired or disputed.
UNASSIGNED_MINERThe deposit names a miner that is not in the committee the chain assigned to the job.
NOT_ATTESTEDThe relay requires attestation (DENDRA_ATTEST_REQUIRE) and this miner is not attested.
EMPTY_ATTRIBUTIONThe write verified but named no address. It is a relay fault: report it.

Three refusals have no reason word. 429 rate limited: one address sent too many requests in a short window, so slow down. 401 unauthorized (X-Dendra-Token): the route takes the shared token and the request carried none or a wrong one. 403 miner not attested: the relay requires attestation and this miner is not attested.

Privacy and security

Your prompt is encrypted from the gateway to the miner; on chain, a job keeps a hash of the prompt and an embedding of the answer, not their text. The relay between them carries ciphertext only. Besides your device, three parties read the prompt and the answer to do their part: the public gateway, which filters the prompt and returns the answer to you; the serving miner, which writes the answer; and, if the job is drawn for audit, the jurors, who judge it.

From kit v0.2.1 the miner seals that reveal for the jurors the chain anchored for the audit and for no other miner; a miner on an earlier kit seals it for every other registered miner. Each copy is sealed to the encryption key the juror registered on chain; for a juror that registered none, to the key the relay serves for it, which a relay that replaces that key can open.

Outside the project, a prompt reaches the public network only through the public gateway: handing it to a miner is a write on the relay's request route, which takes a token the project does not distribute (relay_server.py, Handler._policy). A gateway you run yourself serves your own stack, a separate chain served only by the miners you attach to it, until the relay opens that route to other gateways.

Who can read your prompt: you, in plain text on your device; the Dendra gateway reads it, runs the filter and encrypts it to the miner; the relay carries ciphertext only; the miner reads it to answer it; if the job is drawn for audit, its jurors read the prompt and the answer (a miner on a kit before v0.2.1 seals them for every other registered miner); the chain stores a hash of the prompt, never the prompt, and a public embedding of the answer. Outside the project, a prompt reaches the public network only through the Dendra gateway: handing it to a miner is a write on the relay's request route, which takes a token the project does not distribute. A gateway you run serves your own stack, a separate chain served by the miners you attach to it, until the relay opens that route to other gateways. You plain text on your device, sent over HTTPS Dendra gateway reads it runs the filter, then encrypts it to the miner Relay ciphertext only passes it on, cannot read it Miner memory reads it to answer it, guarded by the miner software Chain prompt: a hash never the prompt; a public embedding of the answer Jurors read it, if drawn A gateway you run serves your own stack, a separate chain, until the relay opens its request route to other gateways. Who can read your prompt: you, in plain text on your device; the Dendra gateway reads it, runs the filter and encrypts it to the miner; the relay carries ciphertext only; the miner reads it to answer it; if the job is drawn for audit, its jurors read the prompt and the answer (a miner on a kit before v0.2.1 seals them for every other registered miner); the chain stores a hash of the prompt, never the prompt, and a public embedding of the answer. Outside the project, a prompt reaches the public network only through the Dendra gateway: handing it to a miner is a write on the relay's request route, which takes a token the project does not distribute. A gateway you run serves your own stack, a separate chain served by the miners you attach to it, until the relay opens that route to other gateways. You plain text on your device, sent over HTTPS Dendra gateway reads it runs the filter, then encrypts it to the miner Relay ciphertext only passes it on, cannot read it Miner memory reads it decrypts it to answer, guarded by the miner software Jurors: read it, if drawn Chain prompt: a hash never the prompt itself; a public embedding of the answer A gateway you run serves your own stack, a separate chain, until the relay opens its request route to other gateways.
  1. You: plain text on your device, sent over HTTPS.
  2. Dendra gateway: reads it, runs the filter, then encrypts it to the miner.
  3. Relay: ciphertext only; it passes the prompt on and cannot read it.
  4. Miner memory: reads it to answer it, guarded by the miner software.
  5. Jurors: if the job is drawn for audit, they read the prompt and the answer to judge it. From kit v0.2.1 only they receive them; a miner on an earlier kit seals them for every other registered miner.
  6. Chain: a hash of the prompt and a public embedding of the answer, never the prompt.
  7. Outside the project, a prompt reaches the public network only through the Dendra gateway. A gateway you run serves your own stack, a separate chain served by the miners you attach to it, until the relay opens its request route to other gateways.

In force

  • Real bonds, slashed on chain when a jury convicts.
  • A verdict needs a strict majority of the jury's voting stake on its side.
  • The relay sees only encrypted data, and the chain stores no prompt or answer text.
  • No module can mint: the supply can only fall.

Live slash and audit counts: slashes.events, jobs.resolved_by_quorum and jobs.deferred_no_jury on https://testnet-proof.dendranetwork.com/proof, with the height they were read at.

Protocol details and sources
  • Conviction rule: antievasion.go::auditSlashDecision.
  • The juror abstains on a missing reveal (the prompt and answer the miner re-encrypts for its jury, from kit v0.2.1 for the anchored jurors only): judge_worker.py, NOREVEAL_ABSTAIN.
  • Work-draw cap, assignment_stake_cap_multiple × min_stake: committee.go::capAssignmentWeights. Audit draw: audit_committee.go::drawMembersWithDomain.
  • The draw pool is frozen when a job opens: a miner registered later cannot be drawn for it: pool_freeze.go::frozenPoolAnchor, minerInFrozenPool.
  • Fixed supply: app/fixed_supply_test.go fails if a minting module or a minter permission appears.

Reference

Endpoints

Paths are on https://testnet-api.dendranetwork.com. Rows that start with a port are on http://testnet-api.dendranetwork.com:<port>. Each row shows what a working route returns.

EndpointWhat it isKeyCode
POST /demo/v1/chat/completionsinference, keyless demo tierno200
POST /v1/chat/completionsinference, keyed tieryes401 without
GET /demo/v1/models · /v1/modelsmodel list, keyless · keyedno · yes200 · 401 without
GET /healthgateway statusno200
GET /capacityhardware inventory, operator-declaredno200
GET /rpc/status · /rpc/validatorsCometBFT RPC through the gatewayno200
GET /rest/cosmos/… · /rest/dendra/…Cosmos REST through the gatewayno200
https://testnet-proof.dendranetwork.com/proofthe proof feed: read-only audit outcomesno200
:26657/status · :26657/validatorsCometBFT RPC, directno200
:1317/cosmos/bank/v1beta1/supply · :1317/dendra/jobs/v1/paramsCosmos REST, direct: supply and parametersno200
GET /network-info.txt · /genesis.jsonjoin configuration and genesis file, over HTTPSno200
:8088/genesis.json · :8088/network-info.txtthe same files, in plain HTTPno200
:4500/faucet: drip size and proof-of-work difficultyno200
:8645/encrypted relay between the gateway and the miners—401

Token facts

FactDetail
Supply10,000,000 DNDR, fixed.
Unitudndr: 1 DNDR = 1,000,000 udndr.
BurnA share of every final fee, fee_burn_bps: 5 % at genesis, governable. A refunded job burns nothing.
RewardsReleased from a pre-allocated Reserve at reserve_release_bps per epoch, a fixed span of blocks: how fast that pool drains, never a yield. Apart from the Final Testnet Season's published rewards, no parameter is a rate, yield or return.
No saleNo token sale, presale or ICO; testnet DNDR is never sold. Faucet grants, the stake, transfers, on-chain job pay and the subsidy are not Final Testnet Season points.

Check the supply: curl -s https://testnet-api.dendranetwork.com/rest/cosmos/bank/v1beta1/supply returns one denom, starting at 10000000000000 udndr. Allocation and emission: litepaper.

Glossary

Client
The account that paid for a job. Behind the public gateway, it is an account the gateway holds.
Genesis
The file that sets the chain's starting state and parameters. "At genesis" means as launched.
Escrow
The client's fee, locked by the chain (in a module account) when the job opens.
Settlement
The answer is recorded on chain; the fee is still held.
Finality
The fee is released, to the miner or back to the client.
bps
Basis points: 10000 = 100 %.
Bond (stake)
The DNDR a miner locks on chain to take work. A conviction takes part of it.
Slash
The share of a convicted miner's bond taken on chain (slash_leak_bps).
Draw (VRF seed)
A random pick made from a per-block seed, the VRF seed: a random value the validators produce and anyone can verify. The work draw assigns a job to a miner; the audit draw picks the jobs to audit and their juries.
Deferred draw
An audit draw postponed because its block lacks enough randomness contributors (committee_min_vrf_contributors) or too few jurors can be seated. The chain retries; a job still unjudged after audit_unwind_blocks is refunded.
Present miner
Proved it was online, or registered, in the current or previous window of avail_epoch_blocks blocks.
Eligible miner
Anchored an answer, or registered, recently enough to sit on a jury.
Jury floor
audit_min_quorum + 1 present, eligible miners: the voters plus the audited miner, who never judges itself.
Voting stake
The bonds of the jurors who voted on an audit.
Reveal
The prompt and answer that an audited miner re-encrypts for its jury: from kit v0.2.1 for the jurors the chain anchored for that audit only, and from an earlier kit for every other registered miner.
LLM-as-judge
A language model that a juror runs to grade another miner's answer.
Relay
The service that carries encrypted prompts and answers between the gateway and the miners. It cannot read them.
Embedding
A list of numbers that sums up what a text means.
Subsidy
A work reward from the Reserve that a paid job opens.
dendrad
The chain's command-line client, inside the node container that join.sh starts: docker compose -f deploy/testnet-node/docker-compose.yml exec -T node dendrad …