Skip to content

[RPC][Mining] Deliver sha256d work over rpc - #1084

Merged
Veil-Project merged 2 commits into
Veil-Project:masterfrom
ohcee:sha256d-mining-rpc-pr
Aug 24, 2026
Merged

[RPC][Mining] Deliver sha256d work over rpc#1084
Veil-Project merged 2 commits into
Veil-Project:masterfrom
ohcee:sha256d-mining-rpc-pr

Conversation

@ohcee

@ohcee ohcee commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

[RPC][Mining] Deliver sha256d work over rpc

Problem

ProgPow and RandomX each let an external miner pull ready made work from the node and hand a solved nonce back, through getblocktemplate (pprpcheader, rxrpcheader) and the pprpcsb / rxrpcsb submit calls. Sha256d never got either side. A sha256d miner had to rebuild the witness merkle root and the accumulator hash on its own and then submit a fully serialized block. That is enough friction that the only sha256d miner anyone actually runs is the one built into the wallet.

Description

This gives sha256d the same rpc mining path the other two proof of work algos already have. getblocktemplate with algo sha256d now returns sharpcheader, the 80 byte hashing header with the 64 bit nonce zeroed, and a new sharpcsb rpc takes that header back with the nonce that solved it and submits the block. The template algo dispatch is now exhaustive, with an explicit randomx case and a defensive error on any value it does not recognise.

The PR is two commits. The first repairs Veil's functional test framework so tests can run at all, a pre-existing bug described under Unit Testing Results. The second is the sha256d rpc feature itself.

Root Cause

Not a regression. When the rpc mining path was added for ProgPow and RandomX, sha256d was left out. The node already assembles a full sha256d block template internally, the in wallet miner uses it, it was just never exposed over rpc, so nothing outside the wallet could mine sha256d without reimplementing the block assembly.

Why broke?

Sha256d is the odd one out structurally. Its work is an 80 byte header whose last 8 bytes are a 64 bit nonce, and building it needs the witness merkle root and the accumulator hash that the node computes while forming the template. With no rpc to hand the finished header over and take a bare nonce back, an external miner has to redo all of that and serialize a whole block to submit. That friction is why the gap sat there so long.

Solution

Expose the work the node already builds. getblocktemplate returns sharpcheader for algo sha256d, and sharpcsb reconstructs the block from the stored template plus the submitted nonce and pushes it through the normal block acceptance path. Consensus is untouched.

How fix?

  • getblocktemplate for algo sha256d stashes the assembled template in mapSha256dTemplates keyed by the header, and returns sharpcheader (80 bytes, nonce zeroed) with a 64 bit noncerange.
  • sharpcsb looks the template up by header, sets the submitted 64 bit nonce, and verifies the solution with the existing CheckProofOfWork(GetSha256DPoWHash(), nBits, consensus) before doing anything else.
  • On a valid solution it submits through ProcessNewBlock, the same call submitblock and the other two algo submit rpcs use, and returns the BIP22 result (null on accept, or duplicate / invalid / inconclusive) exactly like submitblock.
  • The sha_hash argument is present only for signature parity with pprpcsb and rxrpcsb; the node ignores it.
  • The template algo dispatch is made exhaustive so an unknown algo returns a clear error instead of falling through.

No consensus, validation, or proof of work code is touched. The blocks this produces are ordinary sha256d blocks that every other node accepts, and the patched node accepts exactly the same blocks it did before. It is a node local convenience, not a network change, so it needs no fork of any kind.

Unit Testing Results

A new functional test, test/functional/mining_sha256d_rpc.py, covers:

  • getblocktemplate algo sha256d returns an 80 byte sharpcheader with the nonce zeroed and a 64 bit noncerange
  • grinding the nonce and submitting through sharpcsb accepts the block and advances the tip
  • sharpcsb rejects a nonce that does not solve the boundary (error, "Block does not solve the boundary")
  • sharpcsb rejects a header the node never handed out (error, "Block header not found in block data")
  • the accepted block relays to a second node and carries the sha256d version bit
  • a resubmit of the same block reports duplicate

The test cannot run on stock master, because Veil's functional test harness is half renamed from Bitcoin: TestNode takes veild and veil_cli, but add_nodes still passed bitcoind and bitcoin_cli, the default binary paths still pointed at src/bitcoind, and it never answered Veil's wallet seed prompt. That breaks every add_nodes based functional test, not just this one. The first commit in this PR repairs it. With that in place the test passes:

$ test/functional/mining_sha256d_rpc.py
getblocktemplate algo=sha256d returns an 80 byte header and a 64 bit noncerange
Grind the 64 bit nonce over the header blob
sharpcsb rejects a nonce that does not solve the boundary
sharpcsb rejects an unknown header
sharpcsb accepts the solved block
The sha256d block relays and carries the sha256d version bit
A resubmit of the same block reports duplicate
Tests successful

Beyond the unit test, the whole path has been driven end to end on live testnet. An external gpu sha256d miner (OpenCL on an M4 and ccminer on an RTX 3060) mined real testnet blocks through a stratum proxy that pulls sharpcheader from getblocktemplate and submits solved work with sharpcsb. Confirmed testnet sha256d blocks include height 3087602, 3087619, and 3087634 through 3087641.

How to test?

Functional test:

test/functional/mining_sha256d_rpc.py

Manual, on regtest or testnet:

  1. Start veild with -miningaddress set to an address you control.
  2. Call getblocktemplate with {"algo": "sha256d"} and read sharpcheader (80 bytes, the last 8 are the nonce to grind).
  3. Grind the 64 bit nonce until GetSha256DPoWHash of the header meets nBits.
  4. Submit with sharpcsb "<header>" "<sha_hash>" "<nonce>". It returns null on accept, or duplicate / invalid / inconclusive like submitblock.

ohcee added 2 commits August 22, 2026 13:08
The functional test harness was left half renamed from Bitcoin. TestNode
takes veild and veil_cli, but add_nodes still handed it bitcoind and
bitcoin_cli, and the default binary paths still pointed at src/bitcoind
and src/bitcoin-cli, so every test that brings up a node died before it
started. It also never answered Veil's wallet seed prompt.

Pass veild and veil_cli through, default the binaries to src/veild and
src/veil-cli, start nodes with -generateseed=1, and drop the expected
seed backup warning from the stderr check. With this, add_nodes based
functional tests run again.
ProgPow and RandomX both hand an external miner ready made work through
getblocktemplate (pprpcheader, rxrpcheader) and take a bare nonce back
through pprpcsb and rxrpcsb. Sha256d never got either, so a miner had to
rebuild the witness merkle root and the accumulator hash itself and then
submit a fully serialized block, which is why the only sha256d miner in
practice is the one inside the wallet.

Give sha256d the same treatment: getblocktemplate now returns sharpcheader,
the 80 byte hashing header with the nonce zeroed, and sharpcsb takes the
job back with the 64 bit nonce that solved it. Sha256d templates advertise
the wider noncerange, and the algo dispatch is now exhaustive, with an
explicit randomx case and a defensive error on any future unhandled value.

Consensus is untouched; this only exposes work the node already builds.

@seanPhill seanPhill left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK!*

PR Review: #1084 – [RPC][Mining] Deliver sha256d work over rpc

Author: ohcee
Status: Open (awaiting review from seanPhill / Veil-Project)
Commits: 2
Base: master

Summary

This PR closes a long-standing gap: ProgPow and RandomX already expose ready-made work via getblocktemplate + a dedicated submit RPC (pprpcsb / rxrpcsb), but sha256d did not. External sha256d miners previously had to reconstruct the witness merkle root + accumulator hash themselves and submit a full serialized block. That friction meant virtually only the in-wallet miner was usable for sha256d.

The change is purely node-local convenience:

  • getblocktemplate with {"algo": "sha256d"} now returns sharpcheader (80-byte header with 64-bit nonce zeroed) + a 64-bit noncerange.
  • New RPC sharpcsb "header" "sha_hash" "nonce" looks up the stored template, inserts the nonce, verifies PoW with the existing CheckProofOfWork(GetSha256DPoWHash(), ...), then calls ProcessNewBlock exactly like the other submit paths.
  • Algo dispatch is made exhaustive (explicit randomx case + defensive error on unknown values).

Consensus, validation, and PoW rules are untouched. No fork required.

Commit breakdown

  1. d29fea5 – test: repair the functional test framework for Veil
    Necessary prerequisite. TestNode / add_nodes still carried Bitcoin binary names and paths; the wallet seed prompt was also unhandled. This was breaking every add_nodes-based functional test, not just the new one. Clean, focused fix.

  2. ad2b4ae – [RPC][Mining] Deliver sha256d work over rpc
    The feature itself + new functional test.

Code quality & consistency

The implementation deliberately mirrors the existing ProgPow / RandomX paths:

  • Same std::map<std::string, CBlock> pattern (mapSha256dTemplates).
  • Same 60-second last-header reuse / cache.
  • Same clear-on-new-template logic inside getblocktemplate_impl.
  • Same submitblock_StateCatcher + ProcessNewBlock + BIP22 result handling.
  • sha_hash is accepted purely for signature parity with pprpcsb/rxrpcsb and then ignored (identical to how rx_hash is treated in rxrpcsb). Documented in both help text and code.

Key differences that are correct for sha256d:

  • Uses CSha256dInput + midstate (proper for the 80-byte header).
  • 64-bit nonce (nNonce64 + ParseUInt64).
  • Noncerange "0000000000000000ffffffffffffffff".

Minor nits (none blocking):

  • Help-text examples still use a bare 100000 (same as the other two RPCs). Harmless but a hex example would be slightly clearer.
  • Success path converts BIP22 nulltrue (consistent with the existing pprpcsb/rxrpcsb implementations, and the new test asserts True).
  • The three template maps still have no size bound / eviction beyond the full clear on new work. This is pre-existing behaviour; not introduced here.

Testing

New functional test (test/functional/mining_sha256d_rpc.py) is thorough:

  • Correct sharpcheader length / zeroed nonce / noncerange.
  • Grinds a real 64-bit nonce against the target.
  • Rejects unsolved nonce ("Block does not solve the boundary").
  • Rejects unknown header.
  • Accepts valid work, advances tip, relays to second node, carries the sha256d version bit.
  • Resubmit returns "duplicate".
  • Explicitly checks that a bogus sha_hash is still accepted (documents the ignore behaviour).

Author also reports live testnet validation with external miners (OpenCL on M4 + ccminer on RTX 3060 via stratum proxy) producing real blocks (heights ~3087602–3087641).

The framework repair commit is what makes the test (and other functional tests) runnable at all.

Recommendation

Concept ACK + code ACK.

This is a clean, well-scoped, low-risk improvement that brings sha256d external mining to parity with the other two algos. The test coverage is solid, the implementation follows established patterns, and the framework fix is independently valuable.

Happy to see this merged! Nice work.

@Veil-Project Veil-Project left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK

Nice work.

@Veil-Project
Veil-Project merged commit 74008f9 into Veil-Project:master Aug 24, 2026
9 checks passed
@ohcee
ohcee deleted the sha256d-mining-rpc-pr branch August 24, 2026 20:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants