Skip to content

dgb(#82): wire captured-template txs into won-block reconstruct - #303

Merged
frstrtr merged 3 commits into
masterfrom
dgb/82-tx-bearing-wonblock-wire
Jun 21, 2026
Merged

dgb(#82): wire captured-template txs into won-block reconstruct#303
frstrtr merged 3 commits into
masterfrom
dgb/82-tx-bearing-wonblock-wire

Conversation

@frstrtr

@frstrtr frstrtr commented Jun 21, 2026

Copy link
Copy Markdown
Owner

What

Final #82 step: the forced-won live seam now reconstructs a tx-bearing won block instead of coinbase-only.

Wires the #299 bridge + #300 capture store into the reconstruct closure in src/c2pool/main_dgb.cpp (+22/-4):

  1. include template_capture.hpp (dgb: per-job template-retention seam — captured_template_txs_fn provider (#271) #300/dgb(#82): reconstruct won block from captured GBT template, not share refs #271) + template_other_txs.hpp (dgb: template-txs producer bridge (tx-inclusion slice — decode GBT transactions[] into won-block other_txs) #299)
  2. run-loop-scoped dgb::coin::TemplateCapture (outlives all tracker callbacks; declared before ioc.run())
  3. replace the interim coinbase-only template_other_txs_fn stub with make_template_other_txs_fn(template_capture.provider())
  4. seed_forced_from_gbt captures the node-B GBT transactions[] keyed by the forced share hash, so the reconstructor replays the EXACT non-coinbase set the share committed to (merkle-consistent; coinbasevalue already includes those fees -> subsidy balanced)

Why

make_reconstruct_closure_from_template previously got an empty template_other_txs_fn (documented interim coinbase-only). #299 (bridge) + #300 (capture store) are now on master, so the won block can carry the template txs.

Safety

  • Capture MISS -> empty set -> valid coinbase-only block (never fail-closed; logged).
  • Per-coin isolation: src/impl/dgb + main_dgb only; no p2pool-merged-v36 surface.
  • Type-clean: bridge returns exactly the closure 3rd-arg type.

Verification

  • Build: c2pool-dgb green (BUILD_EXIT=0).
  • NEXT (not in this PR): re-soak with a FUNDED regtest mempool to prove a multi-tx won block relays/accepts on both arms; legacy txs first to isolate any BIP141 witness-commitment handling.

Base 6d3dbf6. Operator-tap; not self-merging.

frstrtr added 3 commits June 21, 2026 19:28
Replace the interim coinbase-only template_other_txs_fn stub in the #82
forced-won live seam with the production capture->bridge path:

- declare a run-loop-scoped dgb::coin::TemplateCapture (#300/#271) that
  outlives every tracker callback the provider() is installed into
- feed it through make_template_other_txs_fn (#299) as the reconstruct
  closure template_other_txs_fn, so a won block replays the EXACT
  non-coinbase set the share committed to (merkle-consistent) instead of
  reconstructing coinbase-only
- seed_forced_from_gbt captures the node-B GBT transactions[] keyed by the
  forced share hash; coinbasevalue already includes those fees so the
  regenerated gentx subsidy stays balanced

A capture MISS still decodes to an empty set -> a valid coinbase-only
block (never fail-closed). Per-coin: src/impl/dgb + main_dgb only.
…ector

The tx-bearing reconstruct path (reconstruct_won_block_from_template)
sources its body from the captured GBT template, but assemble_won_block
derived the header merkle_root by walking the share merkle_link
(check_merkle_link). That link only spans the txs it was built over, so a
coinbase-only link with a funded tx in the body emitted a header root for
the coinbase-only set -> daemon rejects bad-txnmrklroot (the #82 funded
multi-tx soak FAIL on both arms).

Recompute the root over [gentx_hash] ++ each other-tx txid via a canonical
BuildMerkleRoot (build_block_merkle_root), set before serialize so the
nonce-grind seam grinds the final header. Coinbase-only is unchanged
(root == gentx_hash). +1 regression KAT; corrected Test 4 which had
enshrined the buggy coinbase-only root with 2 other_txs. 8/8 green.
Fail-closed regtest soak proving a won block carrying a non-coinbase
funded legacy tx is reconstructed (#300/#302/#303) and ACCEPTED by a peer
down BOTH arms (P2P primary + submitblock isolated). Asserts NTX>=2 and
funded-txid presence per arm via getrawmempool/getblock; die() aborts on
any miss (no getrawtransaction-without-txindex false-green path).
@frstrtr
frstrtr merged commit 8270eaa into master Jun 21, 2026
10 checks passed
frstrtr added a commit that referenced this pull request Jun 23, 2026
Fail-closed regtest soak proving a won block carrying a non-coinbase
funded legacy tx is reconstructed (#300/#302/#303) and ACCEPTED by a peer
down BOTH arms (P2P primary + submitblock isolated). Asserts NTX>=2 and
funded-txid presence per arm via getrawmempool/getblock; die() aborts on
any miss (no getrawtransaction-without-txindex false-green path).
frstrtr added a commit that referenced this pull request Jun 23, 2026
dgb(#82): wire captured-template txs into won-block reconstruct
frstrtr added a commit that referenced this pull request Jun 23, 2026
The CoinbaseFirstThenRefOrder test asserted the won-block header
merkle_root equals gentx_hash for the empty-merkle_link case. That held
under the old reconstruct_block_header merkle_link walk, but b91face
(#303 bad-txnmrklroot fix) correctly recomputes the header root over the
ACTUAL block tx vector ([gentx_hash] ++ other-tx txids) so header and
body stay consistent for tx-bearing won blocks. With 2 other_txs the
root is no longer gentx_hash, so the stale assertion failed on master.

Re-pin the assertion to the production invariant via the same
build_block_merkle_root + compute_txid SSOT the assembler uses, so the
test now guards header/body merkle consistency instead of the obsolete
empty-walk identity. Test-only; no behavior change.
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.

1 participant