WIP implement handle_push_solution on jd_server_sv2 + bitcoin_core_sv2#593
WIP implement handle_push_solution on jd_server_sv2 + bitcoin_core_sv2#593plebhash wants to merge 13 commits into
handle_push_solution on jd_server_sv2 + bitcoin_core_sv2#593Conversation
1cc987b to
e394a70
Compare
|
currently, there's no official Bitcoin Core v32 release so this PR is temporarily stubbing ITF to use a binary that's only available locally on my machine once v32 is released I'll fix this PR and CI should be green all integration tests pass locally though, so nothing to worry about |
That seems fine as a first version, but given that new templates may be proposed quite frequently based on fee updates, and that ASIC's may chew on older jobs for a bit, it's a good TODO to try previous templates. Otherwise you completely rely on the JDC/TP to handle the block broadcast for those. (update: I guess it won't fail if only fees changed, so the only concern is stale blocks)
In the https://github.com/2140-dev/bitcoin-capnp-types/blob/master/.github/workflows/ci.yml#L17-L33 And for open pull requests the actual PR branch, e.g. 2140-dev/bitcoin-capnp-types#28
I assume |
that's used for |
e26bc97 to
39c5689
Compare
…idation context Restrict DeclareMiningJob stale-chain-tip classification to actual prev_hash drift and simplify related context state. - classify stale-tip strictly by prev_hash drift (v30x + v31x) - remove redundant min_ntime from ValidationContext - make jd-server drift checks prev_hash-only - prune now-unused BIP34 mempool plumbing/logging - remove unused timestamp from JdResponse::Success - keep timestamp handling local to handler checkBlock assembly - rename remaining timestamp references to ntime for clarity
…mempool_mirror_prev_hash Replace the expensive createNewBlock call (which assembles a full block template with mempool transactions) with a lightweight getTip query. Only the prev_hash is needed for stale-tip detection, so updating just the mirror's prev_hash via getTip is sufficient when the tip changed. Rename force_update_mempool_mirror to force_update_mempool_mirror_prev_hash to make the narrowed scope explicit.
…in-tip When a declared job is already stale at arrival (coinbase built from an old tip), checkBlock returns bad-cb-height but prev_hash may not have drifted during validation. Treat this rejection as stale-chain-tip so that JDC's non-fatal stale path is exercised instead of triggering a fallback.
BIP34 mismatch is no longer detectable on `BitcoinCoreSv2JDP`, which now solely relies on `prev_hash` to detect chain tip drifts that is fine, because if BIP34 drifted, `prev_hash` will be inevitably different that's why we're changing the shape of `assert_jdp_stale_chain_tip_scenario`
Cover the path where a declared job uses a coinbase built from a previous tip that is no longer the current tip at validation time. In this scenario checkBlock rejects with bad-cb-height while no in-handler prev_hash drift occurs, so the handler must map the rejection to stale-chain-tip.
Bitcoin Core submitBlock requires a fully assembled block, so JDS must retain non-coinbase transaction bodies from DeclareMiningJob validation. As a prerequisite for upcoming PushSolution handling with v32 IPC support, JdResponse::Success now carries txdata and no longer returns redundant txid_list. JDS derives txids directly from txdata when validating merkle-root/merkle-path consistency for SetCustomMiningJob, without storing an extra txid cache in DeclaredCustomJob. This addresses an earlier design blindspot and does not change v30/v31 validation behavior.
39c5689 to
55b1f9d
Compare
Reconstruct a full block at JDS when receiving PushSolution and submit it to Bitcoin Core via submitBlock. Follow the clarified Job Declaration semantics from sv2-spec. Reference: stratum-mining/sv2-spec#188 Reference: stratum-mining/sv2-spec#189 Design choice (KISS): JDS keeps only the latest declared custom job per downstream connection and only attempts PushSolution propagation against that entry. It does not attempt propagation for previously declared jobs.
55b1f9d to
600ee71
Compare
| /// Submit a fully assembled block to Bitcoin Core (fire-and-forget). | ||
| /// | ||
| /// This request is currently stubbed as a warning-only no-op by the v30.x and v31.x | ||
| /// backends. | ||
| PushSolution { block: Block }, |
There was a problem hiding this comment.
There was a problem hiding this comment.
another reason to pivot away from this approach:
I'm noticing a lot of JDS log lines like this on my signet e2e tests:
2026-07-19T18:07:28.604132Z WARN bitcoin_core_sv2::unix_capnp::v32x::job_declaration_protocol::handlers: Bitcoin Core rejected block via submitBlock reason=O
k("high-hash") debug=Ok("proof of work failed")
it doesn't happen 100% of the time, because propagation on JDC side is always successful, and I also see JDS log lines like this:
2026-07-19T18:12:07.353926Z WARN bitcoin_core_sv2::unix_capnp::v32x::job_declaration_protocol::handlers: Bitcoin Core rejected block via submitBlock reason=O
k("duplicate") debug=Ok("")
I haven't been able to trace the root cause of the submitBlock failures with 100% certainty, but my suspicion is that the solution is being applied to the wrong custom job, due to DeclareMiningJob vs PushSolution races, which is a direct consequence of the KISS approach of only processing PushSolution against the "latest ACKd DeclareMiningJob"
handle_push_solution on jd_server_sv2 + bitcoin_core_sv2handle_push_solution on jd_server_sv2 + bitcoin_core_sv2
NOT READY FOR REVIEW
close #441
blocked by:
bitcoin-capnp-typesrelease compatible with v32builds on top of:
bitcoin_core_sv2JDPValidationContext#617a few conceptual points worthy of note for reviewers:
##JdRequest::PushSolutionmust carryBlockbefore this PR,JdRequest::PushSolutioncarried aPushSolutionmessagehowever, Bitcoin Core's newsubmitBlockcapnproto method needs a full blockBitcoinCoreSv2JDPdoes not have enough context to reconstruct a full block from aPushSolution, so it's JDS's responsability to do thattherefore,JdRequest::PushSolutionnow carries abitcoin::Blockinstead of aPushSolutionmessage##JdResponse::Successmust carrytxdatabefore this PR,DeclaredCustomJobcarried atxid_list, which was used formerkle_pathvalidation ofSetCustomMiningJobgiven that now it's JDS responsability to reconstruct the full block from aPushSolution,txid_listis no longer sufficientsoJdResponse::Successnow carriestxdatainstead oftxid_listtxid_listis computed fromtxdataformerkle_pathvalidation ofSetCustomMiningJobPushSolutionmust be handled within isolated Downstream Client contextstratum-mining/sv2-spec#189 established that upon receiving
PushSolution, JDS MUST try to reconstruct the block based on the last acknowledgedDeclareMiningJob, and MAY try to reconstruct based on previous oneswe're doing a KISS approach here, where we only try to propagate a solution for the last acknowledged
DeclareMiningJobthis motivated #590 / #592 as a pre-requisite, because otherwise there would be no way to unambiguously associate a
PushSolutionwith aDeclareMiningJobBitcoin Core's new
submitSolutioncapnp methodBitcoin Core's new
submitSolutioncapnp method is being used atbitcoin_core_sv2::unix_capnp::v32x::job_declaration_protocol::BitcoinCoreSv2JDP::handle_push_solutionwhen compared to the previous implementations,
BitcoinCoreSv2JDPgot a new dedicatedsubmit_block_thread_ipc_clientso that we don't block solution submission with regular mempool monitoring activity