Files
drg-xmrig/POOL_INTEGRATION.md
DanS bb1e32aeff Add POOL_INTEGRATION.md (pool migration spec); restore doc/build
- POOL_INTEGRATION.md: exact job/submit format, pool-side validation &
  scoring on the SHA256D pow-hash, and a zero-downtime dual-accept rollout
  plan (deploy dual-accept pool before announcing drg-xmrig).
- Restore doc/build/ docs removed during the initial copy.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 16:51:40 -05:00

105 lines
5.1 KiB
Markdown

# Pool integration & migration guide (drg-xmrig)
`drg-xmrig` mines DragonX with the **pow-hash share model**: it filters every hash on
`SHA256D(header + RandomX(header))` (the block-bearing hash), not on the RandomX hash.
A pool must score shares on that same pow-hash. This document is the spec for updating
the DragonX stratum pool to support `drg-xmrig`, plus a zero-downtime rollout plan.
See `PROTOCOL.md` for the exact byte-level wire format. This file is the pool's view.
---
## 1. Job (pool → miner)
Send a standard XMRig `job` with:
| field | value |
|-------------|-----------------------------------------------------------------------------|
| `job_id` | unique per job |
| `algo` | `rx/dragonx` (aliases also accepted: `rx/hush`, `dragonx`) |
| `blob` | **140-byte** header hex (280 chars): `header[0:108] + nonce[108:140]` |
| `target` | 4- or 8-byte compact target, standard XMRig convention (`diff = 0xFFFF…/target`) |
| `seed_hash` | RandomX seed hash for the current key block |
| `height` | block height |
**Blob layout (140 bytes):** `version(4) + prevHash(32) + merkleRoot(32) + blockCommitments(32) + nTime(4) + nBits(4)` = 108, then a **32-byte nonce field** at `[108:140]`.
**Extranonce (REQUIRED for >1 miner):** the miner only varies the uint32 at `[108:112]`
and copies bytes `[112:140]` **verbatim** into the submitted nonce. So the pool MUST write
a **unique per-connection value into nonce bytes `[112:140]`** (28 bytes) of every blob.
Without it, two miners scan the same 2^32 space and waste work / collide. (This is the
existing extranonce mechanism — it just lives in the upper 28 nonce bytes.)
---
## 2. Submit (miner → pool)
```json
{ "id": "<rpcId>", "job_id": "<job_id>",
"nonce": "<64 hex = full 32-byte nonce field [108:140]>",
"result": "<64 hex = 32-byte RandomX hash>",
"algo": "rx/dragonx" } // present only if pool advertised the "algo" login extension
```
`nonce` is the full 32 bytes = `[4-byte counter | 28-byte extranonce you assigned]`.
`result` is the raw RandomX hash (the PoW *solution*), NOT the double-SHA.
---
## 3. Pool-side validation & scoring
For each submit:
1. Reconstruct the 140-byte header: `blob[0:108]` (from the job you sent) + `nonce[0:32]`
(from the submit, placed at `[108:140]`).
2. **Authenticity:** verify `RandomX(header140, seed) == result`. (Reject otherwise — this
stops a fake `result` + cheap SHA256D from farming credit.)
3. **Pow-hash:** `pow = SHA256D( header140 + 0x20 + result )` (0x20 = compact-size 32).
4. **Block?** `pow <= network_target` → submit block to daemon.
5. **Valid share?** compare the **last 8 bytes** of `pow` (little-endian uint64 at `pow[24:32]`)
against the worker `target` — i.e. `leu64(pow[24:32]) < target`. Credit `shareDiff = 0xFFFF…/target`.
Note: difficulty/target math is the **same** as today's RandomX-share path. The ONLY change
is *which hash* you score: the double-SHA `pow` instead of the RandomX `result`. Block
detection (step 4) is what today's pool already does on every submitted share.
---
## 4. Zero-downtime migration (dual-accept)
The current fleet runs `xmrig-hac` (`XMRig-HAC/6.25.1-hac`), which submits **RandomX-filtered**
shares. If the pool switches to scoring `pow` only, those miners' shares get rejected. So:
**Run both metrics during the transition.** For each submit, after the RandomX authenticity
check, accept the share if it clears the worker target on **either**:
- the RandomX hash `result` (legacy xmrig-hac), **or**
- the pow-hash `pow` (drg-xmrig).
Both represent ~`D` RandomX attempts, so credit `shareDiff` identically — hashrate accounting
stays consistent across both miner types. Block detection (step 4) runs for every accepted
share regardless of metric, so legacy miners keep finding blocks too.
Distinguish miner type (for stats/telemetry only) by login user-agent:
`DRG-XMRig/*` vs `XMRig-HAC/*`.
### Rollout order (important)
1. **Deploy the dual-accept pool first.** It is backward-compatible — the existing fleet is
unaffected (their RandomX shares still credit).
2. **Then announce / publish drg-xmrig.** Early adopters' pow-hash shares now credit
immediately, and their block candidates stop being dropped.
3. Once the fleet has migrated, optionally retire the RandomX-share acceptance path
(pow-only), which also lets you simplify/raise difficulty cleanly.
Do **not** announce drg-xmrig before the dual-accept pool is live, or early adopters will
have shares rejected.
---
## 5. What this fixes
- **Candidate gap:** blocks are a subset of shares, so the pool receives 100% of candidates
(the ~50% under-submission of xmrig-hac 6.25.x pool mode is gone).
- **Hashrate accuracy:** shares are on the block metric, so pool hashrate is directly
comparable to the network hashrate.
- **Nonce overlap:** handled by the per-connection extranonce in nonce bytes `[112:140]`.