Run an Avalon Worker
Start an MDK Worker for a Canaan Avalon device.
Overview
This page details how to run the Canaan Avalon Worker. Select the development (mock) or real-device path.
Prerequisites
Review common deployment prerequisites before you start.
Deployment-specific requirements:
- A Node.js service or script in your deployment that runs the MDK Worker and registers devices
- A supported Avalon device reachable from the machine or container running the Worker
- The miner API reachable over the native CGMiner TCP API, typically port
4028 - A
passwordfor each device: the CGMiner wire protocol itself does not authenticate, but the Worker's own config validation requires this field
Development
Run against a mock
The Avalon Worker ships a mock A1346 that answers the CGMiner API with canned data. Run the mock in one terminal and the Worker in a second, both from the repository root.
-
Start the mock on the CGMiner port:
npm run mock a1346 4028 -
Save this script as
avalon-dev.jsin the repository root. It is the boot call from Connect a miner, pointed at127.0.0.1:'use strict' const os = require('os') const path = require('path') const { getKernel } = require('@tetherto/mdk-core') const { startAvalonWorker } = require('@tetherto/mdk-worker-avalon') const main = async () => { const kernel = await getKernel() const worker = await startAvalonWorker({ workerId: 'avalon-dev', model: 'a1346', storeDir: path.join(os.tmpdir(), 'mdk-dev', 'avalon'), allowedKeys: [kernel.getClientPublicKey()], seedDevices: [{ info: { container: 'dev', serialNum: 'AV-DEV-001' }, opts: { address: '127.0.0.1', port: 4028, password: 'admin' } }] }) await kernel.registerWorker(worker.runtime.getPublicKey()) console.log('Kernel HRPC key:', kernel.getPublicKey().toString('hex')) console.log('Device:', worker.services.provisioning.listDeviceIds()[0]) console.log('Ctrl+C to stop.') } main().catch((err) => { console.error(err); process.exit(1) }) -
Run the script in a second terminal:
node avalon-dev.js
Expected output, with your own key and device ID:
Kernel HRPC key: e9c1f37dc46f5a6a08fcd6d75a697477491e82b9282d9f2d72bee2ab584d0c70
Device: 17aad636-6ebb-4cb0-8865-c7a200625dfe
Ctrl+C to stop.The Kernel then pulls live telemetry (hashrate, power, temperature) from the mock through the Worker. The mock's options are in USAGE.md.
Connect a miner
2.1 Confirm the model
Avalon ships one model family today, a1346 — confirm this against the USAGE.md as new models are added.
2.2 Register your miner
Avalon devices use the native CGMiner TCP API on port 4028. The wire protocol itself does not authenticate, but the
Avalon Worker Plugin's own config validation rejects a device with no password. Add this code to the Node.js
service or script that runs the MDK Worker in your deployment. The snippet shows the minimum boot call seeding one
Avalon device; replace the example IP address and password with your miner's values:
const { getKernel } = require('@tetherto/mdk-core')
const { startAvalonWorker } = require('@tetherto/mdk-worker-avalon')
const kernel = await getKernel()
const worker = await startAvalonWorker({
workerId: 'avalon-rack-1',
model: 'a1346',
storeDir: './store/avalon-rack-1',
allowedKeys: [kernel.getClientPublicKey()],
seedDevices: [{
info: { container: 'site-1', serialNum: 'AV-001' },
opts: { address: '192.168.1.30', port: 4028, password: 'admin' }
}]
})
await kernel.registerWorker(worker.runtime.getPublicKey())allowedKeys lists the RPC callers the Worker accepts. The Worker refuses to start without it
(ERR_WORKER_ALLOWED_KEYS_REQUIRED), so pass the Kernel's client key.
Make sure each miner's IP is reachable from the machine or container running the Worker before registering. Commands act on physical hardware — prioritize thermal safety.
seedDevices only seeds a fresh, empty storeDir — once persisted, the device set survives restarts on its own. To add a device to an already-running fleet, send the registerThing command to the live Worker instead:
const { createMdkClient } = require('@tetherto/mdk-client')
const client = createMdkClient({ kernelKey: kernel.getPublicKey() })
await client.connect()
await client.sendWorkerCommand('avalon-rack-1', null, 'registerThing', {
id: 'AV-002',
info: { container: 'site-1', serialNum: 'AV-002' },
opts: { address: '192.168.1.31', port: 4028, password: 'admin' }
})registerThing persists the device config immediately, but the running Worker does not pick it up until it is stopped and restarted (await worker.stop(), then call startAvalonWorker again with the same storeDir and no seedDevices) — there is no hot-add.
Before running in a deployment, generate the Worker config (common.json for Worker identity, base.thing.json for device defaults and per-model alert thresholds):
cd backend/workers/miners/avalon
./setup-config.shFor the full seedDevices/registerThing option reference and the mock createServer options, see the Worker's USAGE.md and the shared install pattern.
Troubleshooting
A working development run of avalon-dev.js prints Kernel HRPC key: and Device:, then stays running until Ctrl+C.
If the script does not print both values, or if npm run mock reports port 4028 already in use, follow
miner troubleshooting.
Next steps
- Decide how to run the Worker service — Deployment topologies
- Review telemetry units, command shapes, and error codes —
mdk-contract.json