dgb(#82): gentx-bytes -> MutableTransaction unpack (inverse of #173) - #179
Merged
Conversation
…coinbase generate_share_transaction (verification path) and create_local_share (emission path) each open-coded the coinbase wire layout (version|vin|vouts|locktime) and the txid double-SHA256. Two byte paths pinned to the same oracle vector = proven-equivalent, not unified: a third edit could still diverge them. Collapse both onto dgb::coin::assemble_gentx_coinbase() (coin/gentx_coinbase.hpp, the #171 SSOT) so emission == verification == one source. Each call site now only builds its per-share inputs (coinbase script, optional segwit witness-commitment script, PPLNS payout outputs, donation, OP_RETURN ref commitment) and hands them to the assembler; the assembler owns wire framing + txid. PackStream tx is reconstructed from the SSOT bytes so the downstream V36 hash_link diagnostics are byte-for-byte unchanged. No oracle vector regeneration. Single-coin scope: src/impl/dgb/ only. dgb build EXIT=0; dgb_share_test 5/5; dgb_gentx_coinbase_test 3/3.
…its SSOT framing Round-trip equivalence KAT (op_return ref_hash is share-derived, cannot pin a fixed oracle vector): generate_share_transaction(share) txid == verbatim re-derivation through the SAME assemble_gentx_coinbase SSOT. Proves the #172 collapse behaviorally, not structurally. 3/3 PASS, txid 9e2b78d5. Wired into ctest + BOTH build.yml allowlists in this commit (#143 NOT_BUILT trap).
generate_share_transaction computes the coinbase via assemble_gentx_coinbase (the SSOT proven by #172) but returned only the gentx_hash, discarding the bytes. reconstruct_won_block needs the exact non-witness coinbase bytes -- it is block tx[0] and its txid is the merkle leaf -- not just the hash. Add an optional out_gentx (GentxCoinbase*) param, default nullptr: zero change for the verification callers, surfaces {bytes,txid} for the reconstructor. KAT proves the exposed bytes hash to the returned gentx_hash and deserialize into the coinbase MutableTransaction that assemble_won_block frames, round-tripping byte-identically (non-witness). Single-coin (src/impl/dgb/ only); reuses the existing #172 dgb_gentx_share_path_test target (no new allowlist entry).
Won-block reconstructor connecting tissue (sub-slice 1): faithful port of p2pool get_other_tx_hashes ancestry resolution. coin/other_tx_resolver.hpp walks each (share_count, tx_count) ref back share_count generations from the won share (0 == the share itself) and indexes tx_count into that ancestors new_transaction_hashes, preserving ref order = block other_txs order. The two tracker ops (nth_parent / new_transaction_hashes lookup) are injected as callables, mirroring the seam-first decomposition of won_block_dispatch.hpp, so the walk is unit-testable against a synthetic ancestry without a live ShareTracker. Reuses the tracker ancestry walk rather than a flat known_txs map: a flat lookup cannot reproduce how the sharechain addresses a tx and diverges on duplicate txids or refs past the locally-known set. Malformed refs (tx_count OOB, share_count past chain end) throw rather than emit a wrong hash. 6 gtests pin self-share/walk-back/order/empty/both throws. Single-coin (src/impl/dgb/ only); no shared base / p2pool-merged-v36 surface. Test wired into ctest + both build.yml --target allowlists (#143).
…b-slice 2) Won-block reconstructor connecting tissue (sub-slice 2): coin/other_tx_assembler.hpp bridges the ordered other_tx hash list from resolve_other_tx_hashes (sub-slice 1) to the deserialized MutableTransaction vector that assemble_won_block frames as txs = [gentx] ++ other_txs. Faithful port of the known_txs lookup in p2pool data.py Share.as_block: other_txs = [known_txs[h] for h in transaction_hashes]. The known-tx lookup is INJECTED as a (hash) -> const MutableTransaction* callable (nullptr == unknown), mirroring the seam-first decomposition of sub-slice 1 and won_block_dispatch.hpp, so the bridge is unit-testable against a synthetic known-tx set without a live mempool. A missing hash THROWS std::out_of_range rather than dropping/placeholder-filling the tx: a block with a missing other_tx has the wrong merkle root and is daemon-rejected, so loud failure is strictly safer than emitting a malformed block. Witness framing is not decided here -- the txs are returned verbatim and the block witness shape stays governed by assemble_won_block`s TX_WITH_WITNESS conditional codec. DGB is segwit-active (SEGWIT_ACTIVATION_VERSION, v36 >= it), so the path is live; the KAT pins that a witness-bearing other_tx flips the assembled block to the witness codec via the other_tx leg, not gentx-only. dgb_other_tx_assembler_test: 5/5 PASS -- order-preserve, missing-throws, empty, end-to-end resolve->assemble->frame (coinbase-first, ref order), witness reachability. Wired into test/CMakeLists.txt + both build.yml --target allowlists (#143 NOT_BUILT trap). Per-coin isolation: src/impl/dgb/ only; p2pool-merged-v36 surface: NONE.
…me as_block Tie the three landed sub-slices into the single composition the dispatch handler injects as its WonBlockReconstructor: resolve_other_tx_hashes (#174) -> assemble_other_txs (#176) -> assemble_won_block (#168 framing) Faithful port of p2pool data.py Share.as_block: produces {bytes, hex} for broadcast_won_block dual path. Gentx enters as a deserialized MutableTransaction + txid (the SSOT gentx-bytes -> MutableTransaction unpack, inverse of #173 exposure, is the next slice). Injected tracker/known_txs seams keep it unit-testable; out_of_range propagation from each step preserved (never emit a partial/wrong block). dgb_reconstruct_won_block_test 5/5 PASS: end-to-end == manual resolve+assemble+frame (byte-identical), [gentx]++others in ref order, empty-refs gentx-only, ref-past-chain + unknown-known-tx throw. Wired into test/CMakeLists.txt + both build.yml --target allowlists (#143 trap). Per-coin isolation: src/impl/dgb/ only. p2pool-merged-v36 surface: none.
coin/gentx_unpack.hpp: unpack_gentx_coinbase() turns the share SSOT non-witness gentx bytes (generate_share_transaction out_gentx, #173) back into the MutableTransaction reconstruct_won_block injects at block tx index 0. Parses with TX_NO_WITNESS so the coinbase round-trips its non-witness bytes EXACTLY and the txid (== gentx_hash, consumed by the merkle_root walk) stays stable -- no witness/serialization drift; throws std::out_of_range on trailing bytes (malformed gentx). gentx_unpack_test: 6/6 oracle round-trip (no-segwit + witness-commitment layouts, byte-exact + txid stable + HasWitness false), coinbase-shape recovery, inverse-pairing vs assemble_gentx_coinbase, and trailing-byte throw. Wired into test CMake + both build.yml --target allowlists. src/impl/dgb/ only; p2pool-merged-v36 surface NONE.
frstrtr
force-pushed
the
dgb/gentx-unpack
branch
from
June 19, 2026 01:44
209435c to
02049a9
Compare
frstrtr
added a commit
that referenced
this pull request
Jun 19, 2026
…(--run) Stand up the run-loop spine in main_dgb.cpp behind a new --run flag: a boost::asio::io_context plus an explicit graceful shutdown driven from signal_set(SIGINT, SIGTERM), mirroring main_btc.cpp s teardown contract. This is the lifecycle every node subsystem (sharechain peer dgb::Node, embedded digibyted P2P, Stratum acceptor) and the #82 won-block dispatch handler hangs off. Standing the spine up first keeps the next increments (node/Config construction over LevelDB, P2P listen, Stratum, and the m_on_block_found -> reconstruct_won_block -> broadcast_won_block binding landed across #163/#166/#167/#173/#174/#176/#177/#179) build-verifiable rather than landing a large unverified port in one step. --selftest / bare invocation unchanged (live ShareTracker::score() path). External digibyted RPC fallback posture preserved. Build: c2pool-dgb links EXIT=0 (-DCOIN_DGB=ON). Smoke: --selftest OK (block_period=75s SSOT); --run spine up, SIGINT -> clean shutdown exit 0.
frstrtr
added a commit
that referenced
this pull request
Jun 19, 2026
…(--run) Stand up the run-loop spine in main_dgb.cpp behind a new --run flag: a boost::asio::io_context plus an explicit graceful shutdown driven from signal_set(SIGINT, SIGTERM), mirroring main_btc.cpp s teardown contract. This is the lifecycle every node subsystem (sharechain peer dgb::Node, embedded digibyted P2P, Stratum acceptor) and the #82 won-block dispatch handler hangs off. Standing the spine up first keeps the next increments (node/Config construction over LevelDB, P2P listen, Stratum, and the m_on_block_found -> reconstruct_won_block -> broadcast_won_block binding landed across #163/#166/#167/#173/#174/#176/#177/#179) build-verifiable rather than landing a large unverified port in one step. --selftest / bare invocation unchanged (live ShareTracker::score() path). External digibyted RPC fallback posture preserved. Build: c2pool-dgb links EXIT=0 (-DCOIN_DGB=ON). Smoke: --selftest OK (block_period=75s SSOT); --run spine up, SIGINT -> clean shutdown exit 0.
frstrtr
added a commit
that referenced
this pull request
Jun 19, 2026
…(--run) Stand up the run-loop spine in main_dgb.cpp behind a new --run flag: a boost::asio::io_context plus an explicit graceful shutdown driven from signal_set(SIGINT, SIGTERM), mirroring main_btc.cpp s teardown contract. This is the lifecycle every node subsystem (sharechain peer dgb::Node, embedded digibyted P2P, Stratum acceptor) and the #82 won-block dispatch handler hangs off. Standing the spine up first keeps the next increments (node/Config construction over LevelDB, P2P listen, Stratum, and the m_on_block_found -> reconstruct_won_block -> broadcast_won_block binding landed across #163/#166/#167/#173/#174/#176/#177/#179) build-verifiable rather than landing a large unverified port in one step. --selftest / bare invocation unchanged (live ShareTracker::score() path). External digibyted RPC fallback posture preserved. Build: c2pool-dgb links EXIT=0 (-DCOIN_DGB=ON). Smoke: --selftest OK (block_period=75s SSOT); --run spine up, SIGINT -> clean shutdown exit 0.
frstrtr
added a commit
that referenced
this pull request
Jun 19, 2026
…(--run) Stand up the run-loop spine in main_dgb.cpp behind a new --run flag: a boost::asio::io_context plus an explicit graceful shutdown driven from signal_set(SIGINT, SIGTERM), mirroring main_btc.cpp s teardown contract. This is the lifecycle every node subsystem (sharechain peer dgb::Node, embedded digibyted P2P, Stratum acceptor) and the #82 won-block dispatch handler hangs off. Standing the spine up first keeps the next increments (node/Config construction over LevelDB, P2P listen, Stratum, and the m_on_block_found -> reconstruct_won_block -> broadcast_won_block binding landed across #163/#166/#167/#173/#174/#176/#177/#179) build-verifiable rather than landing a large unverified port in one step. --selftest / bare invocation unchanged (live ShareTracker::score() path). External digibyted RPC fallback posture preserved. Build: c2pool-dgb links EXIT=0 (-DCOIN_DGB=ON). Smoke: --selftest OK (block_period=75s SSOT); --run spine up, SIGINT -> clean shutdown exit 0.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Inverse of #173 GentxCoinbase exposure: coin/gentx_unpack.hpp unpack_gentx_coinbase() turns the share SSOT non-witness gentx bytes back into the MutableTransaction reconstruct_won_block injects at block tx index 0.
KAT (dgb_gentx_unpack_test, 6/6 PASS, build EXIT=0): oracle round-trip for both no-segwit + witness-commitment-first layouts (byte-exact re-serialize + txid stable + HasWitness false), coinbase-shape recovery, inverse-pairing vs assemble_gentx_coinbase (txid == GentxCoinbase.txid), trailing-byte throw. Vectors reused from gentx_coinbase_test (oracle frstrtr/p2pool-dgb-scrypt).
Wired into test CMake + both build.yml --target allowlists (#143 NOT_BUILT trap avoided). src/impl/dgb/ only; p2pool-merged-v36 surface: NONE. Stacked on #177 (c48328d). HOLD merge — lands bottom-up on operator-approved card.