dgb(phase-b): lift PPLNS weight walk into shared SSOT (step 1) - #333
Merged
Conversation
frstrtr
added a commit
that referenced
this pull request
Jun 22, 2026
Same bar as the #328 payout-split invariance KAT: prove the #333 lift of generate_share_transaction() step-1 into compute_pplns_weight_walk() moves ZERO weight. Embed the pre-refactor inline walk verbatim as legacy_inline_weight_walk() and assert the helper reproduces it weight-for- weight (per-script weights, total_weight, total_donation_weight) across a battery: V36 decay path, pre-V36 grandparent-start + max_weight cap, donation split, full-donation zero-addr-weight share, the insufficient-depth guard (both throw identically), null/absent parents, and a chain exceeding the real_chain_length window. Each weight map is then fed through the #328 payout-split SSOT and the outputs + donation asserted byte-identical, closing the end-to-end no-payout-satoshi-drifts proof shared by the emission and verification paths. dgb_share_test 28/28.
…T helper Replace the inline steps 2-3 of the share verification SSOT generate_share_transaction() (PPLNS amount math + consensus output ordering) with a call to coin/pplns_payout_split.hpp compute_pplns_payout_split(). The helper is a verbatim lift of that inline math; delegating collapses the two copies into a single consensus implementation so the per-connection Stratum coinbase assembler and the verifier can never diverge on a payout satoshi. Behavior-neutral by construction (same formulae, finder fee, >=1-sat V36 donation floor + (amount, script) tiebreak, ascending sort truncated to [-4000:]). The helper oracle-vector KAT (dgb_pplns_payout_split_test) pins the values against p2pool-merged-v36; the verifier-path framing tests (dgb_gentx_share_path_test, dgb_gentx_coinbase_test) stay green, proving the share path still emits identical coinbase framing. Stacked on dgb/pplns-payout-split (helper extraction).
build_connection_coinbase_from_pplns delegates the payout split to compute_pplns_payout_split() -- the same helper generate_share_transaction (the share verification path, #329) calls -- instead of taking pre-resolved payout_outputs/donation_amount. The coinbase a miner hashes per-connection and the coinbase the share check enforces are now byte-identical on every payout satoshi by construction: one payout implementation, not two kept in agreement. Pure delegation + field forwarding into build_connection_coinbase_parts; no inline payout arithmetic. dgb-tree-only. 4 delegation-identity KATs (V36, pre-V36 finder fee, segwit/ref forwarding, value anchor); 8/8 green. Stacks on the #328/#329 PPLNS SSOT stack.
…via producer seam Replace the empty build_connection_coinbase() stub with a delegation to build_connection_coinbase_from_pplns (the #330 SSOT that itself routes through the single compute_pplns_payout_split the verifier calls). A new set_pplns_inputs_fn producer seam supplies the PPLNS weight map (walked from the ShareTracker), ref_hash, subsidy and donation script; the tracker walk stays in main_dgb where the ShareTracker + CoinParams are in scope, so no sharechain logic leaks into the work source. Fenced: while the seam is UNBOUND (or returns nullopt) the method is byte-identical to the pre-wire stub (empty job, no work pushed) -- runtime behavior is unchanged until main_dgb binds the producer (follow-on slice). The emitted coinb1/coinb2 are byte-identical to the verifier per a KAT comparing the wired output to the SSOT called directly with the same inputs. 3 KATs added (empty-until-wired, byte-identical delegation, nullopt->empty); dgb_work_source_test 26/26 green.
Extract generate_share_transaction() step-1 PPLNS tracker walk into dgb::coin::compute_pplns_weight_walk(), the producer-side counterpart of the steps 2-3 lift in pplns_payout_split.hpp (#328). The share-verification path and the per-connection Stratum coinbase emission path now draw one tracker-walk implementation, so the weight map a miner hashes cannot drift from the one the verifier enforces. Verbatim lift: exact V36 depth-decay vs pre-V36 grandparent-start branch, the data.py insufficient-depth guard, and the block-target/spread max_weight cap are unchanged. Result type is deduced from the tracker (decltype) to avoid the share_tracker.hpp <-> share_check.hpp include cycle. KAT WeightWalkSSOTContract locks the helper contract (verbatim V36 forward + safe-empty on null/absent parent); the unchanged generate_share_transaction fixtures prove value-level byte-identity. dgb_share_test 27/27, dgb_connection_coinbase_test 8/8.
Same bar as the #328 payout-split invariance KAT: prove the #333 lift of generate_share_transaction() step-1 into compute_pplns_weight_walk() moves ZERO weight. Embed the pre-refactor inline walk verbatim as legacy_inline_weight_walk() and assert the helper reproduces it weight-for- weight (per-script weights, total_weight, total_donation_weight) across a battery: V36 decay path, pre-V36 grandparent-start + max_weight cap, donation split, full-donation zero-addr-weight share, the insufficient-depth guard (both throw identically), null/absent parents, and a chain exceeding the real_chain_length window. Each weight map is then fed through the #328 payout-split SSOT and the outputs + donation asserted byte-identical, closing the end-to-end no-payout-satoshi-drifts proof shared by the emission and verification paths. dgb_share_test 28/28.
frstrtr
force-pushed
the
dgb/pplns-weight-walk-ssot
branch
from
June 22, 2026 15:39
c8d4408 to
46b7b0a
Compare
This was referenced Jun 22, 2026
frstrtr
marked this pull request as ready for review
June 22, 2026 16:58
frstrtr
added a commit
that referenced
this pull request
Jun 23, 2026
Same bar as the #328 payout-split invariance KAT: prove the #333 lift of generate_share_transaction() step-1 into compute_pplns_weight_walk() moves ZERO weight. Embed the pre-refactor inline walk verbatim as legacy_inline_weight_walk() and assert the helper reproduces it weight-for- weight (per-script weights, total_weight, total_donation_weight) across a battery: V36 decay path, pre-V36 grandparent-start + max_weight cap, donation split, full-donation zero-addr-weight share, the insufficient-depth guard (both throw identically), null/absent parents, and a chain exceeding the real_chain_length window. Each weight map is then fed through the #328 payout-split SSOT and the outputs + donation asserted byte-identical, closing the end-to-end no-payout-satoshi-drifts proof shared by the emission and verification paths. dgb_share_test 28/28.
frstrtr
added a commit
that referenced
this pull request
Jun 23, 2026
dgb(phase-b): lift PPLNS weight walk into shared SSOT (step 1)
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.
Stacked on #331. Phase B.
What
Extract
generate_share_transaction()step-1 PPLNS tracker walk into the shared SSOTdgb::coin::compute_pplns_weight_walk()— the producer-side counterpart of the steps 2-3 lift (compute_pplns_payout_split, #328). The share-VERIFICATION path and the per-connection Stratum coinbase EMISSION path now walk the tracker through one implementation, so the weight map a miner hashes cannot drift from the one the verifier enforces.Why
This is the prerequisite for the upcoming main_dgb seam-bind (binding
set_pplns_inputs_fnto the live tracker lambda). Collapsing the walk into an SSOT before the bind removes the divergence risk from the bind itself — the bind becomes a thin call into already-verified code.Faithfulness
max_weightcap are byte-unchanged.decltype) to avoid theshare_tracker.hpp↔share_check.hppinclude cycle.WeightWalkSSOTContractKAT locks the helper contract (verbatim V36 forward + safe-empty on null/absent parent). The unchangedgenerate_share_transactionfixtures prove value-level byte-identity.Tests
dgb_share_test27/27 ·dgb_connection_coinbase_test8/8 (local). GPG-signed.Consensus-bearing (touches the verifier) → surface-for-tap, not auto-merge.
Reviewer focus — decltype-deduced return type (per integrator)
The one spot where a "verbatim lift" could silently differ is the deduced
Result. Confirmed byte-identical to a hand-named type:share_tracker.hpp:1701declaresCumulativeWeights get_v36_decayed_cumulative_weights(...)— return by value, a concrete non-reference struct.decltype(tracker.get_v36_decayed_cumulative_weights(...))over that call-expression yields exactlyCumulativeWeights(a function-call prvalue, so decltype is the declared return type, unchanged). No reference qualifier, no narrowing, no copy-vs-ref change of the weight map.Result out{};value-initializes the result; a reference deduction would be ill-formed and fail to compile. The 27/27 build is that proof.CumulativeWeightsdirectly would be behavior-identical but reintroduces the share_tracker.hpp <-> share_check.hpp include cycle — the only reasondecltypeis used here.Net: emission and verification share one weight-map type by construction; the decltype is a cycle-break, not a type change.