Skip to content

Add checkblock RPC and checkBlock() to Mining interface

Introduce checkBlock() on the Mining interface for IPC, as well as a new checkblock RPC that's easier to use than getblocktemplate in proposal mode, and supports weak blocks.

Rationale

Verifying block templates (no PoW)

Stratum v2 allows miners to generate their own block template. Pools may wish (or need) to verify these templates. This typically involves comparing mempools, asking miners to providing missing transactions and then reconstructing the proposed block.1 This is not sufficient to ensure a proposed block is actually valid. In some schemes miners could take advantage of incomplete validation2.

The Stratum Reference Implementation (SRI), currently the only Stratum v2 implementation, collects all missing mempool transactions, but does not yet fully verify the block.3 There's currently no way for it to do so, short of re-implementing Bitcoin Core validation code.

(although SRI could use this PR, the Template Provider role doesn't need it, so this is not part of #31098)

Verifying weak blocks (reduced PoW)

Stratum v2 decentralises block template generation, but still hinge on a centralised entity to approve these templates.

There used to be a decentralised mining protocol P2Pool4 which relied on (what we would today call) weak blocks. In such a system all participants perform verification and there is no privileged pool operator (that can reject a template).

P2Pool shares form a "sharechain" with each share referencing the previous share's hash. Each share contains a standard Bitcoin block header, some P2Pool-specific data that is used to compute the generation transaction (total subsidy, payout script of this share, a nonce, the previous share's hash, and the current target for shares), and a Merkle branch linking that generation transaction to the block header's Merkle hash.

IIUC only the header and coinbase of these shares / weak blocks were distributed amongst all pool participants and verified. This was sufficient at the time because fees were negligible, so payouts could simply be distributed based on work.

However, if P2Pool were to be resurrected today5, it would need to account for fees in a similar manner as PPLNS2 above. In that case the share chain should include the full weak blocks6. The client software would need a way to verify those weak blocks.

A similar argument applies to Braidpool.

Enter checkblock and its IPC counterpart checkBlock()

Given a serialised block, it performs the same checks as submitblock, but without updating the block index, chainstate, etc. The proof-of-work check can be bypassed entirely, for the first use of verifying block templates. Alternatively a custom target can be provided for the use case of weak blocks.

When called with check_pow=false the checkblock RPC is (almost) the same as getblocktemplate in proposal mode, and indeed they both call checkBlock() on the Mining interface.

Implementation details:

TestBlockValidity() is moved to the ChainstateManager and refactored to no longer return BlockValidationState. This avoids the new checkBlock() method needing to pass BlockValidationState over IPC.

The refactor commit contains additional changes explained in its commit message.

Another commit drops support for the unused BlockValidationState encoding.

This PR contains a simple unit test and a more elaborate functional test.

Potential followups:

  • if the block contains "better" transactions, (optionally) add them to our mempool 5
  • keep track of non-standard transactions7
  • allow rollback (one or two blocks) for pools to verify stale work / uncles
  1. https://github.com/stratum-mining/sv2-spec/blob/main/06-Job-Declaration-Protocol.md

  2. https://delvingbitcoin.org/t/pplns-with-job-declaration/1099/45?u=sjors 2

  3. https://github.com/stratum-mining/stratum/blob/v1.1.0/roles/jd-server/src/lib/job_declarator/message_handler.rs#L196

  4. https://en.bitcoin.it/wiki/P2Pool

  5. this improves compact block relay once the real block comes in 2

  6. The share chain client software could use compact block encoding to reduce its orphan / uncle rate. To make that easier, we could provide a reconstructblock RPC (reconstructBlock IPC) that takes the header and short ids, fills in a CBlock from the mempool (and jail) and returns a list of missing items. The share chain client then goes and fetches missing items and calls the method again. It then passes the complete block to checkblock. This avoids the need for others to fully implement compact block relay. Note that even if we implemented p2p weak block relay, it would not be useful for share chain clients, because they need to relay additional pool-specific data.

  7. https://delvingbitcoin.org/t/second-look-at-weak-blocks/805

Merge request reports

Loading