1. What you need from the node
Your own KRNX node (or access to one) with thekrnx namespace enabled:
Chain profiles:
2. krnx_getMiningInfo
krnxBlockNumber in the template) and has to reach the chain before the
head has moved inclusionWindowBlocks - 1 blocks past that anchor. Later than that
it is stale_work. See §10.
3. krnx_getBlockTemplate
Request
The Bitcoin GBT
mode field is accepted but pointless here: the only allowed value
is "template", and that is what a missing field means anyway. "mode":"proposal"
is rejected with unsupported_mode — this API has no block-validation mode.
The coinbase reserves exactly 30 bytes for extradata. A longer tag is
truncated, not refused: 31 bytes gets you a template with a 30-byte tag. The
limit counts UTF-8 bytes rather than characters, and the cut lands on a rune
boundary — 16 two-byte characters (32 bytes) come back as 15, never as 15 and a half
of one. invalid_extradata is left for one case only: input that is not valid UTF-8.
Anything shorter than 30 bytes is zero-padded to exactly 30, so your tag never
changes the coinbase length.
Extranonce values only matter if you want the node to return a template with them
already spliced in (and, for ZEC, a finished coinbaseTx). On the Bitcoin-family
chains a pool normally sends zeros and splices its own — see §5.
Response
Full parent transactions are not in the response and never will be: the pool mines a
header, the coordinator assembles the parent block.
Byte order and prefixes
The most common source of silent bugs. The rule: Bitcoin-style fields arrive without0x, KRNX-style fields with 0x.
On submit it flips:
parentHeader and coinbaseTx travel as 0x-hex. So the
ZEC coinbaseTx from the template has to go back with a 0x prepended.
4. How the coinbase is built
The node builds the coinbase itself and hands it over in two halves. A pool does not compose one — it only inserts the extranonce. Inside the scriptSig:fabe6d6d is the standard merged-mining marker (as in Namecoin and Dogecoin). Its
tree holds the KRNX leaf that binds your beneficiary to the proof of work found.
That is exactly why the scriptSig cannot be rewritten and the outputs cannot be
swapped: the node verifies the commitment and rejects the share.
The coinbase outputs (coinb2) are signed by the coordinator and compared byte for
byte.
coinb1 ends right before the 12-byte extranonce slot; coinb2 starts right after
it:
5. Building work: BCH, LTC, RVN
5.1 Coinbase and merkle root
merkle[::-1].hex() must equal t["merkleroot"].
The pool is free to roll its own extranonce — those 12 bytes are yours, and you do
not need a fresh template for it.
5.2 The 80-byte header (BCH, LTC)
- BCH:
int.from_bytes(dsha(header), "little") <= target - LTC:
int.from_bytes(scrypt(header, header, N=1024, r=1, p=1, dkLen=32), "little") <= target
5.3 The 120-byte header (RVN, KawPoW)
KawPoW is not fed the header itself but the hash of its first 80 bytes:
mix_hash and rejects a header whose committed mix does not
match, so there is no point in filling it with junk. nHeight comes from the
template’s height: a different height is a different DAG epoch.
RVN’s stratum dialect is the ethash-style one (mining.notify with a seed hash),
not the Bitcoin one.
6. Building work: ZEC (Equihash)
ZEC is the one chain where the pool does not assemble the coinbase. Rewriting a Zcash scriptSig moveshashAuthDataRoot, and recomputing that requires the auth
digests of every other transaction in the block, which a pool never sees. So the
node hands over finished values:
coinbaseTx— the complete v5/v6 coinbase transaction;merkleroot— the root for it;blockcommitments— the finishedhashBlockCommitmentsfield.
coinb1/coinb2 are present in the ZEC response for shape compatibility, but you
cannot build the coinbase from them: with your own extranonce there is nothing
to recompute blockcommitments with. If you need a different extranonce, request a
new template with different extranonce1/extranonce2. In practice you never need
to: Zcash has a 32-byte nonce, which is plenty of search space on its own.
The header is 140 bytes of PoW header + fd 40 05 + 1344 bytes of solution =
1487 bytes.
The target comparison runs against the block id:
mining.notify
fields are in the serialized header’s own byte order, with none of the Bitcoin
reversals.
7. What you may change and what you may not
Free — this is the search space:
Not allowed — the node checks and rejects:
Check order on the node: every cheap comparison first, PoW last. Deliberately so —
KawPoW and Equihash are the only steps whose cost the submitter chooses.
8. Targets: KRNX share vs parent block
The template’starget is the only bar a pool needs. Clear it and the share
earns a KRNX reward.
You do not need to watch for shares that also solve the parent chain: the node says
so itself, in the parentBlockCandidate field of the submit response. Such a share
is picked up by the coordinator and relayed to the parent network; it changes
nothing about the KRNX reward.
Set your own vardiff as usual — it must be no weaker than target, or most shares
come back as low_difficulty.
9. Submitting a share
One call; the fields are the same for all four methods:Success
workshareId is derived from immutable fields and comes out the same on any node:
Errors
Anything other thanaccepted/known arrives as a JSON-RPC error with code
-32042:
data.reason, never on the message text:
10. Refreshing work
- Poll
krnx_getBlockTemplateroughly once per second. - A changed
workidmeans changed work: a new signed template, a new KRNX anchor, a new DAA target or a different beneficiary. Issue a new job. - Set
clean_jobs=trueonly when the parent block’s identity changes (height,previousblockhash,bits,powId). Aworkidchange on its own does not invalidate outstanding jobs: they stay acceptable while their anchor is in the window. - The window from §2: a share whose anchor is older than
inclusionWindowBlocks - 1blocks getsstale_work. The one exception is a share that cleared the parent target — accepted as*_submit_only, but with no KRNX reward. mintimeis the lower bound fornTime,now + 2hthe upper one. Roll time freely between them.
11. Checking the reward
workshareId or the pair powId + powHash, where
powHash is the hash field from the submit response. Exactly one of the two.
The response carries status (included / locked / not found), includedBlockNumber,
confirmations, beneficiary, baseReward / feeReward / totalReward and
unlockTime. The method is reorg-aware: it re-checks that the inclusion block is
still canonical.
12. A complete minimal client (sha256d)
13. Integration checklist
beneficiaryin the response equals your KRNX address, lower-cased.- With the extranonce from your request, your recomputed merkle root equals the
template’s
merkleroot— that proves your reversals are right. - The first share comes back
status: accepted,candidateMode: reward. - Resending the same share returns
status: knownwith the sameworkshareId— idempotency works and your accounting will not double-count. pendingShareCountgrows, andkrnx_getWorkshareRewardon theworkshareIdshows inclusion in a block.- Your
stale_workrate is near zero. If it is not, you refresh templates too rarely. - Your
low_difficultyrate is near zero. If it is not, your vardiff is weaker thantarget.
Further reading
Mining the main chain
kHeavyHash, the kaspa stratum dialect, and the node-to-stratum contract for
a Kronex main-chain pool.
What a block pays
How the sealer, the uncles and the workshares in a block share its reward,
and when those coins unlock.

