Get Started
Run a Worker on Testnet
Workers are the supply side of the Lightchain AI network. A worker runs whitelisted models via Ollama alongside the Worker Sidecar (shipped as a Docker image), claims inference sessions directly on-chain, streams answers to users through the public Worker Gateway, and earns fees for every completed job. This guide walks through the end-to-end lifecycle on Testnet — from generating a worker key and funding it to registering on-chain, going live, and deregistering when you're done. Testnet runs in dispatcher-free mode: no central service hands out jobs. Your worker watches the chain, wins sessions by sortition, and serves them itself — see Dispatcher-free Mode for how that works. Everything below configures the external profile from that page: no Redis, no VPN, no inbound ports.Prerequisites
- Docker installed (the image is
linux/amd64) - GPU machine with enough VRAM for your model (8 GB+ for
llama3-8b) - Ollama installed and running
- Funder wallet holding at least 5,050 LCAI (5,000 stake + a gas buffer for claim, ack, blob and completion transactions) — this is your existing wallet that pays to bring the worker online. It is NOT the worker key. You will generate a fresh worker key in Step 0 and send LCAI from the funder to it in Step 5.
- Foundry installed (
castis used for key generation, balance checks, and contract reads) - Outbound HTTPS/WSS — nothing needs to be opened inbound
Network reference
Resolve testnet contract addresses
AIConfig, JobRegistry and SessionManager are deployed at runtime, so their addresses depend on the environment. Resolve them once from the predeployed WorkerRegistry and export them — the env file in Step 4 picks them up from your shell:
CodeBASH
Step 0: Generate a fresh worker key
Always use a dedicated, brand-new key for the worker. Do not reuse your funder key — the worker key sits in a Docker container with the keystore password, and should hold only the working capital (stake + small gas buffer) you're comfortable exposing to that machine.CodeBASH
Address and Private key, then export them:
CodeBASH
CodeBASH
$WORKER_ADDR. If it doesn't, stop and re-export — anything sent to the wrong address is unrecoverable, and registering with mismatched keys locks the stake on the wrong account.
Do not set WORKER_PRIVKEY to your funder's private key. The two must be different. The funder pays from your existing wallet (Step 5); the worker is the new key from this step.
Step 1: Install Ollama and pull the model
On-chain model names are the Ollama tags, used verbatim (the on-chainmodelId is keccak256(name)). Pick from Whitelisted models and pull each one into Ollama. Only llama3-8b and llama3-70b are not native Ollama tags — create them as aliases:
CodeBASH
Step 2: Pull the worker image
CodeBASH
/bin/worker (the sidecar, default entrypoint) and /bin/lightchain-worker (the operator CLI for keys, registration, preflight, drain, balance and release).
Step 3: Import the worker private key
Imports$WORKER_PRIVKEY (set in Step 0) into an encrypted keystore on disk:
CodeBASH
Address: printed by the command must equal $WORKER_ADDR from Step 0. If they differ, stop — the wrong key was imported.
Step 4: Write the worker env file
The sidecar and the CLI read the same variables, so keep them in one file. Write it from the shell where you resolved the addresses (the$… values expand from your exports):
CodeBASH
<YOUR_PASSWORD> with the keystore password from Step 3. Every docker run below passes this file with --env-file.
Generate the ECDH encryption key
Every worker advertises an encryption public key on-chain so users can encrypt prompts for it —keygen produces that pair locally:
CodeBASH
Step 5: Fund the worker from your funder wallet
Send LCAI from your funder wallet (the existing one mentioned in Prerequisites) to$WORKER_ADDR (the fresh address from Step 0). The worker needs at least 5,050 LCAI: 5,000 for the minimum stake plus a gas buffer — in dispatcher-free mode the worker also pays for its own claimSession transactions, so keep more than the ~1 LCAI the old dispatcher flow needed.
If your funder wallet is in MetaMask/Rabby, send the transfer through the wallet UI. If you have its private key locally and want to use Foundry:
CodeBASH
CodeBASH
Common mistake: setting FUNDER_PRIVKEY to the same value as WORKER_PRIVKEY. That sends LCAI from the worker to itself (a no-op minus gas) and the worker stays unfunded. Cross-check with cast wallet address --private-key "$FUNDER_PRIVKEY" — it must NOT equal $WORKER_ADDR.
Step 6: Register on-chain
CodeBASH
- Stake 5,000 LCAI (auto-queried from
AIConfig) - Register your ECDH public key on-chain
- Add every model in
SUPPORTED_MODELSto your supported models
You can only serve models that are currently whitelisted on AIConfig. Attempting to register for a delisted or non-existent model will revert.
Step 7: Preflight
preflight is a read-only check of everything above in one go — RPC and chain id, registration, suspension, stake against the live on-chain minimum, wallet balance, local ECDH key vs the on-chain key, each model's whitelist / enabled / added state, gateway login, Ollama tags, and the beacon API. It prints one line per check and exits 1 if anything fails, so it is safe to run as often as you like:
CodeBASH
CodeTEXT
preflight --worker 0xADDRESS inspects any address without a keystore — paste its output when asking for help.
Step 8: Run the worker
The--add-host flag below makes host.docker.internal resolve to the Docker host on Linux (where it isn't provided by default). On macOS and Windows it's a no-op — Docker Desktop already maps that hostname — so the same command works everywhere.
CodeBASH
Step 9: Verify it's working
CodeBASH
CodeTEXT
CodeBASH
claimed session request followed by the per-job stages:
CodeBASH
preflight (Step 7) first — the usual causes are a model-name mismatch or a suspension.
Whitelisted models
All of these are registered onAIConfig and whitelisted on WorkerRegistry (values as of 2026-09-13; read the live fee with cast call $AI_CONFIG_ADDRESS "getModelFee(bytes32)(uint256)" $(cast keccak <name>)):
To serve several models, list them comma-separated in SUPPORTED_MODELS (for example SUPPORTED_MODELS=llama3-8b,gemma4:e2b), pull each into Ollama, and re-run register (or add-models for a worker that is already registered). Every model name must match the on-chain name exactly — a different string hashes to a different modelId and the registration reverts with ModelNotWhitelisted.
Rewards and fund handling
Per-job fees earned by the worker are paid out directly to the worker's wallet ($WORKER_ADDR from Step 0) as jobs complete. There is no separate payout address registered on-chain and no automatic forwarding to the funder wallet — earnings simply accumulate on the worker key.
Because the worker key lives inside the Docker container alongside its keystore password, you should not treat it as long-term storage. Sweep accumulated fees to your own designated wallet (typically the funder, a hardware wallet, or any cold-storage address you control) on whatever cadence matches your risk tolerance.
Check the worker's current balance:
CodeBASH
CodeBASH
Do not drain the worker wallet to zero while the worker is registered and running — it needs gas to claim sessions and to ack and complete jobs. A worker that cannot pay for a transaction misses its deadline, and missed deadlines lead to slashing (see Slashing & Rehabilitation). Top up from your funder if it dips.
WorkerRegistry, not by the worker wallet, and is only released when you deregister (see Deregister and withdraw stake).
Check registration status
preflight (Step 7) is the most complete check. For the bare on-chain registration flags:
CodeBASH
Slashing and suspension
Workers that miss deadlines or lose disputes get their stake slashed. After three offenses the worker is automatically suspended for 7 days and must callWorkerRegistry.reinstate() to come back online. During the current dispatcher-free transition the slash rates are set to 0 on testnet, but offences are still recorded. Full mechanics, live rates, and the step-by-step recovery runbook are in Slashing & Rehabilitation.
Stopping and draining
In dispatcher-free mode a running worker keeps claiming sessions until the process stops, sodrain alone does not take it out of rotation. Stop it with a grace period longer than the sidecar's shutdown timeout:
CodeBASH
deregister sequence — deregister reverts with ActiveJobsExist until the dispute window plus a release cycle has passed.
Deregister and withdraw stake
Run this only after confirmingactiveJobsCount is 0 — otherwise it reverts with ActiveJobsExist. See Drain & Graceful Exit for the full flow.
CodeBASH
Stop the worker
Only safe afterderegister succeeded — see Drain & Graceful Exit for why removing the container earlier can orphan claimable earnings.
CodeBASH
Troubleshooting
Testnet contract addresses
Related guides
- Dispatcher-free Mode — run profiles, environment reference, web search, stopping a self-claiming worker.
- AIVM EL Architecture — how inference, verification, and slashing fit together.
- Worker API — the indexer and data model for worker/job activity.
- Model Governance — how models get whitelisted and priced.
- Run a Node — consensus-layer node operation (separate role from a worker).
- Run a Worker on Mainnet — production guide once you're ready to commit real LCAI.