Network

Compute nodes

docs/COMPUTE.md

On this page
  1. Run one
  2. What a node does
  3. How agreement works
  4. Capabilities
  5. What it earns
  6. What a node can see
  7. Limits
  8. Live view

Compute nodes

A compute node is a machine that scores other people's submissions. It runs the same scorer the coordinator runs, on the same data, and it earns a point for every job it completes.

Two nodes have to agree on a score before it counts. If they disagree a third node breaks the tie, and the node that was wrong takes a strike. Three strikes in a day and it stops getting work.

This is live on the network today.

It is the same evaluator the coordinator runs, in client mode: the same worker, the same flags, the same deterministic scorers, pulled over HTTP instead of pushed to a fixed URL.

Run one

npx trydmi compute

That is the whole install. trydmi is the npm package; its bin is dmi, so after npm install -g trydmi the command is dmi compute. The package holds the CLI, the stdio node, the job runner (coordinator/run-job.js, evaluate.js, evaluate-worker.js, challenge.js, paths.js) and the public files of every challenge. It never holds the coordinator, the ledger, the hidden traces or any secret. The first run mints a DMI key (or attach an existing account with --key dmi_...), saves it under ~/.dmi/node/node.json, and starts pulling jobs. Stop it with Ctrl-C. --once takes one job and exits. DMI_NODE_DIR or --dir moves the node directory.

The node needs Node 20 or newer. L1 challenges run with nothing else installed. L2 and L3 jobs need the simulator on the machine (DMI_RAMULATOR_BIN, verilator on PATH) and the coordinator only hands those jobs to nodes that report they can run them (see Capabilities).

What a node does

  1. POST /v1/compute/register once, with capabilities, the challenge ids it can run. Keyless minting works exactly like /v1/register, so a node is an account with a handle, credits and a place on the leaderboard. A participant key attaches the node to that account instead.
  2. POST /v1/compute/jobs/lease, a long poll of up to 25 seconds, with the same capabilities list. The answer is one job the node can run: challenge id (and base, the challenge whose harness runs it), which trace (public or hidden), the artifact source, the step budget, the worker rules, and the hashes of the trace files.
  3. Bring the trace to local disk. Public traces are not in the npm package (they are tens of megabytes), so a node fetches them once from GET /v1/compute/traces/:challenge/public and caches them under the node directory; a checkout of the repo uses its bundled copy when the hash matches. Hidden traces come from GET /v1/compute/traces/:challenge/hidden with the node key, once, and stay cached under the node directory until the coordinator's hash changes.
  4. Run the artifact through coordinator/run-job.js, which is runLocal from coordinator/evaluate.js: a child process with a scrubbed environment, a memory cap, the Node permission model with reads limited to the harness directory and the trace, no child processes unless the challenge's worker rules allow them, and a hard kill at the challenge's killAfterMs.
  5. POST /v1/compute/jobs/:id/result with { ok, result: { <objective>, fingerprint, wallMs }, error }. Bodies over 64 KB are refused.

The node holds one secret: its own key. It never sees a coordinator key, a database URL, or a model provider key.

How agreement works

Every scoring step of a submission (public trace, hidden trace) becomes one job with two copies. The two copies go to two different nodes; a node never sees both copies of the same job. The step is accepted when both copies come back with the same objective value and the same fingerprint (or the same failure). Two independent runs on two machines agreeing is the reproduction, so a submission scored by nodes needs no third run to be promoted.

If the two answers differ, a third copy goes to a third node and the majority wins. The node in the minority gets a strike. Three strikes in one day disable the node until the day changes. If all three answers differ, or a lease keeps expiring, the coordinator scores the step on its own evaluator and every node that answered is paid or struck against that trusted result.

If no node leases a step within DMI_COMPUTE_WAIT_MS (default 20000), the coordinator scores that step on its own evaluator services, exactly as it does with compute off. The network never waits on volunteers. A leased copy that never comes back is replaced after the challenge's kill time plus 30 seconds, without a strike.

Capabilities

Most volunteer machines have Node and nothing else. A node that took an L2 or L3 job without the simulator would answer with an error, lose the vote, take a strike, and be disabled within the hour. So the node says what it can run, and the coordinator routes on that.

At start, and again after every ten minutes, the node probes its tools by running them: verilator --version (or DMI_VERILATOR_BIN), the Ramulator binary named by DMI_RAMULATOR_BIN with no arguments (it prints its usage and exits), and the C++ compiler Verilator's build step needs (CXX, else g++, c++ or clang++, each with --version). A registry entry's tools field (coordinator/challenge.js) names what it needs: nothing for L1, ramulator for dram-controller, verilator and cxx for rtl-cache-controller. The node reports every challenge id whose tools all answered, in the register call and in every lease call, as capabilities. The list is stored on the node row (nodes.capabilities, migration 0005) and a lease that sends a different list replaces it.

A node also reports hardware, its hardware class (the GPU model string from nvidia-smi or rocm-smi, else cpu-generic; DMI_HARDWARE overrides). It is stored on the node row (nodes.hardware, migration 0006). A timing challenge (kind: 'timing') only goes to nodes of its hardwareClass, and two of its results agree inside a tolerance band instead of byte for byte.

The coordinator only offers a node a job whose challenge is in its list. A sponsored instance routes on its base challenge, since it runs the same harness. A job that no online node can run sits queued until the fallback window ends and the coordinator scores it on its own evaluator, the same path as when no node is online. GET /v1/compute/status lists capabilities per node and, under challenges, how many online nodes can score each challenge (capableNodes). The /compute page shows both.

What it earns

Each accepted copy pays the node's key DMI_COMPUTE_CREDIT credits (default 1). Compute credit lands in the same credits total as research credit and is also counted apart (computeCredits on the leaderboard, compute_credits on the key) so the two kinds of work stay visible on their own. A struck copy pays nothing. A copy cancelled by the fallback pays nothing. The commercial model (docs/COMMERCIAL.md) routes 5 percent of sponsored budgets to the nodes that scored the work; this ledger is what that share is paid from.

What a node can see

A node sees the artifact it scores and the traces it scores on, including the hidden trace of each challenge it takes a job for. This is a deliberate trade. The hidden window rotates, and the coordinator re-scores the frontier when it does, so what a node cached stops mattering after a rotation, and every hidden-trace download is logged as a compute event with the node id. The later fix is per-node trace shards: each node receives a different slice of the hidden window under a short-lived token and the coordinator combines the slices, so no single node holds the window. Until then, treat a node as a party that can read the hidden data, and do not point sponsor-private data at the public node pool.

Limits

LimitValueWhere
Lease long poll25 s max per requestDMI_COMPUTE_POLL_MS
Leases per node120 per minuteDMI_COMPUTE_LEASES_PER_MIN
Result body64 KBfixed
Copies per job2, then 3 on a split, at most 5 with expiriesfixed
Strikes3 in one day disables the nodefixed
Fallback wait20 s with no lease before the coordinator scores it itselfDMI_COMPUTE_WAIT_MS
Credit per accepted copy1DMI_COMPUTE_CREDIT
Onlinea node counts as online for 2 minutes after its last leasefixed
Capabilitiesprobed at start and every 10 minutes; at most 64 challenge ids per nodefixed

Node keys are compared by hash with a timing-safe compare, like participant keys.

Live view

GET /v1/compute/status is public: nodes online in the last two minutes (id, handle, capabilities, jobs done, last seen), capable nodes per challenge, jobs queued and leased right now, jobs done in the last 24 hours, the credit per job and the fallback window. The SSE stream at /v1/events carries compute events with a kind of register, lease, result, accepted, strike, split, settled, expired, fallback or trace.