stratum: RandomX pool mining support + reference miner (stratummine)

The stratum server was hardcoded for legacy Equihash (1347-byte solution,
sol.begin()+3 offset, CheckEquihashSolution) and was off-by-default with a
"do not use on RandomX" warning. DragonX is RandomX, so external pool mining
was impossible. This wires RandomX end-to-end.

Server (stratum.cpp), branched on ASSETCHAINS_ALGO == ASSETCHAINS_RANDOMX:
* GetWorkUnit sets StratumWork.nHeight and, for RandomX, sends the per-height
  RandomX key via a new mining.set_randomx_key message (a miner cannot derive
  it without the chain). The legacy mining.notify format is unchanged.
* SubmitBlock/stratum_mining_submit accept a 32-byte solution (== the RandomX
  hash, used as nSolution verbatim) and validate it with CheckRandomXSolution
  instead of CheckEquihashSolution. Target check (GetHash() < target) and the
  nNonce = extranonce1||extranonce2 assembly are shared with the equihash path.
* -stratumtarget=<hex> overrides the pool share target (default diff-1); lets a
  solo/low-difficulty test miner accept easy shares.
* GetWorkUnit's IsInitialBlockDownload guard is bypassed under -testnode=1 so an
  isolated low-work test chain can serve work.

Reference miner: `stratummine "host" port ("address" timeout)` RPC (rpc/mining.cpp,
POSIX-only). A minimal stratum client that subscribes/authorizes, receives work +
the RandomX key, varies nNonce, hashes with RandomX via GetRandomXInput (byte-
identical to CheckRandomXSolution) and submits a 32-byte solution. Off-the-shelf
Equihash/Monero miners can't speak DragonX's 256-bit-nNonce Zcash header, so this
is the reference implementation. Added to the rpc client arg-conversion table.

Validated: loopback (chain 0->4, accepted every time, verifychain=true) AND a real
2-box LAN run (Linux miner -> Mac stratum server, 3 blocks accepted, verifychain=true).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-27 20:24:13 -05:00
co-authored by Claude Opus 4.8
parent 1745ee4e63
commit 2232868d9f
4 changed files with 330 additions and 33 deletions
+5 -4
View File
@@ -621,6 +621,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageGroup(_("Stratum server options:"));
strUsage += HelpMessageOpt("-stratum", _("Enable stratum server (default: off)"));
strUsage += HelpMessageOpt("-stratumtarget=<hex>", _("Pool share target (64-hex, big-endian; larger = easier). Default is the diff-1 target. Useful for solo/low-difficulty mining."));
strUsage += HelpMessageOpt("-stratumaddress=<address>", _("Mining address to use when special address of 'x' is sent by miner (default: none)"));
strUsage += HelpMessageOpt("-stratumbind=<ipaddr>", _("Bind to given address to listen for Stratum work requests. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces)"));
strUsage += HelpMessageOpt("-stratumport=<port>", strprintf(_("Listen for Stratum work requests on <port> (default: %u or testnet: %u)"), BaseParams().StratumPort(), BaseParams().StratumPort()));
@@ -991,10 +992,10 @@ bool AppInitServers(boost::thread_group& threadGroup)
RPCServer::OnPreCommand(&OnRPCPreCommand);
if (!InitHTTPServer())
return false;
// WARNING: the stratum server (stratum.cpp) is Equihash-era code: it assumes a 1347-byte
// Equihash solution and calls CheckEquihashSolution. It has NOT been updated for DragonX's
// 32-byte RandomX solution and must not be relied on for mining without a full revalidation.
// It stays off by default (DEFAULT_STRATUM_ENABLE=false); only -stratum turns it on.
// Stratum server (stratum.cpp) supports DragonX's RandomX PoW (32-byte solution + per-height
// RandomX key conveyed to the miner) as well as legacy Equihash, branched on ASSETCHAINS_ALGO.
// Off by default (DEFAULT_STRATUM_ENABLE=false); only -stratum turns it on. Needs a RandomX-aware
// stratum miner (see contrib/ reference miner) — stock Equihash/Monero miners won't work.
if (GetBoolArg("-stratum", DEFAULT_STRATUM_ENABLE) && !InitStratumServer())
return false;
if (!StartRPC())