krnx_getWork
and returns a nonce through krnx_submitWork. The pool does not need to
identify how the template was produced: treat its fields as opaque and use
them unchanged.
The main-chain proof of work is kHeavyHash: two cSHAKE256 passes, a 64×64
matrix, and a little-endian result comparison. A miner that supports this
algorithm can mine KRNX without changing its hashing implementation.
Two rules break an integration if you do not account for them:
getWork()[10]always contains milliseconds: parse the hex asuint64and pass it without any further unit conversion. Section 4.- Share difficulty and consensus difficulty are different scales, exactly 2^32 apart. Section 5.
1. What the node must provide
Your own KRNX node with HTTP-RPC and template production enabled:
The reward goes to the node’s etherbase, not to the stratum login. The login
is only an accounting label; payouts are the pool’s own business.
Three RPC methods, nothing else:
All three are mirrored in the
eth_ namespace (eth_getWork, eth_submitWork) —
the names match stock krnxd, so existing ethash pool code only needs its hashing
swapped out.
2. krnx_getWork
Work is new when
[0] changes. Everything else in the header is already folded
into that hash.
If the node is not mining or is still syncing, the method returns an error. That
is normal: wait, and do not close the stratum port.
Push instead of polling
With--miner.notify http://pool:1234/work, the node POSTs the selected JSON
work array whenever the template changes. Polling krnx_getWork every 200–500
ms is a practical alternative. --miner.notify.full carries the KRNX header
and does not implement this work-array contract, so use the ordinary array or
polling.
3. The kHeavyHash pre-image
KRNX uses this fixed pre-image:first = cSHAKE256(data, customization="ProofOfWorkHash")→ 32 bytes.matrix = generate(PRE_POW_HASH)— a 64×64 matrix of 4-bit values from xoshiro256++ seeded with the seal hash, regenerated until its rank (float64 Gaussian elimination, eps = 1e-9) reaches 64.mixed[i] = first[i] XOR (product[2i]<<4 | product[2i+1]), whereproduct[i] = (Σ matrix[i][j] * vector[j]) >> 10andvectorholds the nibbles offirst.final = cSHAKE256(mixed, customization="HeavyHash")→ 32 bytes.- The PoW value is
finalread little-endian. A block is solved when that value is<=the target.
Golden vector
Every implementation must reproduce exactly this:TestKHeavyHashPowValueGolden
(consensus/kheavyhash/kheavyhash_test.go). Every example in section 10 is checked
against it.
4. The timestamp: always milliseconds
work[10] always contains the exact uint64 TIME placed in the kHeavyHash
pre-image, in milliseconds. KRNX Header.Time itself remains in seconds for
the EVM, DAA, reward lockups, and every other chain rule, but a pool must not
derive PoW time from the header or convert units itself.
A miner parses [10] as a 64-bit integer and places it in the pre-image exactly
as received. Multiplication, division, or storage in uint32 changes or
truncates the pre-image, so the node rejects the resulting solutions. The rule
is: send exactly the numeric value from work[10] without unit conversion.
Where to get it
Use onlywork[10], the hex-encoded numeric millisecond value:
work[9] contains a second-based KRNX header.Time, but it is a different field
with a different purpose. Do not compare it with [10] or use it to identify a
work type. The standard three-parameter krnx_submitWork path requires no such
classification.
Do not roll TIME
A pool must not roll TIME along with the nonce.work[0] and work[10] form one
immutable job. Fetch a new template to obtain a new time.
5. Difficulty: two scales
Stratum difficulty 1 is worth about 2^32 hashes. Hence:
- Do not hard-code the starting difficulty — derive the band from the current
network difficulty: start at
netdiff/8, floor atnetdiff/4096, ceiling atnetdiff. - The ceiling is the
netdiffderived from[2]: above it every share is already a network solution, and the pool goes blind to a miner that produces nothing. - A share that solves a block is always accepted, even when it misses the current vardiff bound.
Σ (share_difficulty * 2^32) / elapsed.
6. KRNX Stratum interface
Example full exchange:Two job formats
Ordinary: the seal hash read as four little-endian uint64s:mining.subscribe user agent.
Extra nonce
The prefix occupies the high bytes of the 64-bit nonce; the miner rolls the rest. Two prefix bytes give 65536 connections and 48 bits of search space each. Never hand out more than three: an ASIC exhausts what is left in a fraction of a second. On submit a miner sends either all eight bytes (0x0001000000000527) or only its
own part (000000000527). When fewer than 16 - len(prefix) hex characters
arrive, the pool prepends the prefix itself.
7. Submitting a block
The answer is
true when the node accepts the solution for processing, or
false. A successful response alone does not mean that the KRNX height has
already changed. false means one of:
- the node no longer holds work with that
powHash— a stale; - the PoW misses the target — the pool and the node disagree on the pre-image, most often the timestamp;
- the block is too old relative to the current height.
Extra. It is outside the universal public contract: some node-selected
templates are immutable, so an external pool should always use the ordinary
three-parameter call.
Do not tie the submission to the miner’s socket: a miner may drop the connection
right after solving, and the block still has to go out. Ask for fresh work
immediately after a submit — the template is spent either way.
8. Splitting work across connections
The universal method is to partition the 64-bit nonce space. The pool assigns a unique high-byte prefix throughmining.set_extranonce, and the miner scans the
remaining low bits. Connections may share one PRE_POW_HASH while searching
disjoint nonce sets.
A two-byte prefix provides 65,536 independent 48-bit spaces. Keep the assigned
prefix with the connection, reconstruct the full 64-bit nonce on
mining.submit, and send it through the ordinary three-parameter
krnx_submitWork call.
This works for every job selected by the node. The public RPC does not currently
guarantee a distinct PRE_POW_HASH per connection; that requires node-side
issuance of derived jobs.
9. What you may and may not change
Free:
Not allowed:
10. Code examples
Complete working clients (fetch work → decode the timestamp → compute difficulty → scan nonces → submit a block) live indocs/examples/kheavyhash-pool/. All of them are
checked against the golden vector from section 3 and run against a live node.
Python and Node.js are fast enough to validate an integration, not to hash for
real.
Below is the core of each implementation: building the pre-image and both
cSHAKE256 passes.
10.1 Go
10.2 Node.js
10.3 Rust
Own implementation on thesha3 crate:
10.4 Python
11. Direct integration checklist
krnx_getWorkanswers, and[0]changes when the template does.- Your hasher reproduces the golden vector from section 3.
- The timestamp comes from
[10]asuint64milliseconds without conversion. mining.notifyships the seal hash such that a miner rebuilds exactly[0]from the four words.- Difficulty is set on the (2^224−1)/diff scale and below the block difficulty.
- A share that solves a block is accepted even if it misses the vardiff bound.
krnx_submitWorkreturnstrue; the pool does not infer a new height from this response and tracks the nextpowHashseparately.- The node’s rejection rate is near zero. If it is not, see section 12.