dgb(#82 4b/4c): scrypt_pow.hpp digest CALL SSOT + satisfaction-gate KAT - #286
Merged
Conversation
Land the foundational slice of embedded real work-gen: coin/scrypt_pow.hpp wraps btclibs scrypt_1024_1_1_256(80-byte header) and decodes the 32-byte digest via the existing u256::from_le_bytes (dgb_arith256.hpp), closing the documented "the scrypt CALL itself lands at the ingest boundary in a following slice" TODO. Single SSOT so the nonce grinder (next slice) and the header_chain ingest boundary can never disagree on PoW byte order. V36 Scrypt-only: this is the ONLY PoW digest DGB validates; the other four algos are accept-by-continuity and never reach here. dgb_scrypt_pow_test (5/5): pins the digest bytes over a fixed header (vector captured from btclibs scrypt itself, the DGB-Scrypt algo SSOT) and proves the little-endian decode compares correctly against SetCompact-shaped targets the way header_chain.hpp satisfaction gate does (pow_hash <= target, MSB-first). Reuses header_chain_test scrypt TU set (real scrypt, header-only u256, no core / no OBJECT lib). Registered in CMake + both build.yml --target allowlists. End-to-end agreement with DigiByte Core is proven by the live node-B ACCEPT integration test (4b/4c tip-extension bar), not this unit KAT.
grind_won_nonce(header80, target) increments the 80-byte header nonce [76..79] LE until scrypt_pow_hash(header) <= target -- the EXACT header_chain.hpp satisfaction gate -- calling THROUGH the #286 digest CALL SSOT (never a bypass hash), so a nonce it accepts is one node B ACCEPTs. This is the missing primitive between the faithful won-block reconstruction and a ProcessNewBlock ACCEPT: the leg-2 A/B delivery proof reached node B but was consensus-rejected high-hash precisely because the forced-won seam carried no real PoW. Fails closed: returns nullopt when no nonce satisfies inside the budget (or the full 2^32 space wraps) -- a header that does not satisfy its target is never broadcast, mirroring the reconstructor loud-throw. dgb_nonce_grinder_test (5/5): finds a satisfying nonce well inside budget, the winning header satisfies the gate and its reported digest == the SSOT digest, the winning nonce is written LE into [76..79], re-grinding from the winner succeeds on iter 1, and an unsatisfiable target exhausts the budget to nullopt. Reuses the _dgb_scrypt_tus real-scrypt set; header-only u256, no core / no dgb OBJECT lib. Added to both build.yml --target allowlists. Fenced src/impl/dgb/ + build.yml. Wiring grind -> reconstruct -> submit on the live forced-won path and the node-B ACCEPT gate proof are the explicitly-next integration slice.
…KAT)
regrind_block_nonce: grind the header nonce of an ALREADY-FRAMED
reconstructed-block blob (reconstruct_won_block_from_template {bytes})
until its DGB-Scrypt PoW digest satisfies the parent target, writing the
winning nonce back into header [76..79] IN PLACE. The missing wiring
between the faithful won-block reconstruction (merkle root fixed) and a
node-B ProcessNewBlock ACCEPT: the A/B delivery proof reached node B but
was consensus-rejected "high-hash" because the forced-won seam carried
no real PoW.
Ordering invariant enforced structurally: runs only on an already-framed
block (merkle root set FIRST by reconstruct), mutates ONLY header bytes
[76..79], never the merkle region [36..67] or tx tail. Hash via the #286
scrypt_pow_hash SSOT only; satisfaction = the exact pow <= target gate
header_chain.hpp runs. Fail-closed (nullopt, bytes UNCHANGED) on a runt
blob or exhausted budget.
KAT 5/5: reground header satisfies target via SSOT; only [76..79] mutate
(merkle + tx tail byte-preserved); runt-blob fail-closed; exhausted-budget
fail-closed; deterministic. Reuses the _dgb_scrypt_tus real-scrypt set;
header-only, no core / no OBJECT lib. Both build.yml --target allowlists.
Per-coin isolation: src/impl/dgb/ only. p2pool-merged-v36 surface: NONE.
frstrtr
added a commit
that referenced
this pull request
Jun 21, 2026
The missing composition between leg-2's faithful won-block reconstruction and a node-B ProcessNewBlock ACCEPT. finalize_won_block_pow takes a reconstructed block (header[0..79] with merkle_root already set -- merkle FIRST, integrator-pinned ordering) and grinds the nonce at [76..79] THROUGH grind_won_nonce -> scrypt_pow_hash (the #286 digest CALL SSOT) until the DGB-Scrypt PoW satisfies the parent target, splices the winning nonce back, and regenerates the RPC-fallback hex in lockstep with the P2P-arm bytes. This closes the "high-hash, proof of work failed" rejection: the forced-won seam reached node B but carried no real PoW. SSOT call-through, never a bypass hash -- a finalized block is by construction one node B's own Scrypt validation accepts. Fail-closed (nullopt) on sub-80-byte input or no-nonce-in-budget, mirroring make_reconstruct_closure's never-a-partial-block posture. Standalone-guard discipline: depends ONLY on nonce_grinder.hpp (real btclibs scrypt + header-only u256); no core, no dgb OBJECT lib, no util/HexStr (local lowercase encoder, byte-identical to HexStr). Test links the SAME _dgb_scrypt_tus set as dgb_nonce_grinder_test. +5 KATs (dgb_won_block_finalize_test, 5/5 green): finalized header pow<=target via the same SSOT; winning nonce spliced LE into [76..79]; hex == bytes; ONLY the 4 nonce bytes mutate (merkle + tx tail untouched); fail-closed on a 79-byte input. Registered in BOTH build.yml --target allowlists (#143 trap). Fenced: src/impl/dgb/** + build.yml allowlist only. p2pool-merged-v36 surface: NONE. DGB-Scrypt standalone parent in the V36 default build.
frstrtr
added a commit
that referenced
this pull request
Jun 21, 2026
The missing composition between leg-2's faithful won-block reconstruction and a node-B ProcessNewBlock ACCEPT. finalize_won_block_pow takes a reconstructed block (header[0..79] with merkle_root already set -- merkle FIRST, integrator-pinned ordering) and grinds the nonce at [76..79] THROUGH grind_won_nonce -> scrypt_pow_hash (the #286 digest CALL SSOT) until the DGB-Scrypt PoW satisfies the parent target, splices the winning nonce back, and regenerates the RPC-fallback hex in lockstep with the P2P-arm bytes. This closes the "high-hash, proof of work failed" rejection: the forced-won seam reached node B but carried no real PoW. SSOT call-through, never a bypass hash -- a finalized block is by construction one node B's own Scrypt validation accepts. Fail-closed (nullopt) on sub-80-byte input or no-nonce-in-budget, mirroring make_reconstruct_closure's never-a-partial-block posture. Standalone-guard discipline: depends ONLY on nonce_grinder.hpp (real btclibs scrypt + header-only u256); no core, no dgb OBJECT lib, no util/HexStr (local lowercase encoder, byte-identical to HexStr). Test links the SAME _dgb_scrypt_tus set as dgb_nonce_grinder_test. +5 KATs (dgb_won_block_finalize_test, 5/5 green): finalized header pow<=target via the same SSOT; winning nonce spliced LE into [76..79]; hex == bytes; ONLY the 4 nonce bytes mutate (merkle + tx tail untouched); fail-closed on a 79-byte input. Registered in BOTH build.yml --target allowlists (#143 trap). Fenced: src/impl/dgb/** + build.yml allowlist only. p2pool-merged-v36 surface: NONE. DGB-Scrypt standalone parent in the V36 default build.
frstrtr
added a commit
that referenced
this pull request
Jun 21, 2026
…ssify->dispatch) [#82 leg-2 / Stage 4d] Replace the Stage-4a mining_submit stub with the live hot path. Reconstruct the 80-byte DGB block header from the JobSnapshot + miner inputs (coinbase = coinb1||en1||en2||coinb2; merkle ascent from the coinbase txid; header = version|prev|merkle|ntime|nbits|nonce, all little-endian / prevhash reversed to internal order), run the DGB-Scrypt PoW digest through the #286 scrypt_pow SSOT, expand both compact targets via compact_to_target, and classify via the Stage-4d submit_classify SSOT (tighten-first): WonBlock -> serialize the full block (BIP144 coinbase witness when segwit active) and hand it to the dual-path broadcaster submit_block_fn (P2P relay + submitblock RPC fallback, #82); scream-never-drop on a won block that reaches no sink. ShareAccept -> forward the found-share fields to try_mint_share (the #295 producer seam -> #294 mint bind); degrades to accepted-without- credit when no mint fn is wired (no silent drop). Reject -> stratum low-difficulty error. work_source.cpp / work_source_test.cpp only; per-coin isolation held. The header layout is byte-for-byte Bitcoin (only the PoW digest differs, Scrypt); no share format, coinbase commitment, or PPLNS math touched -> p2pool-merged-v36 surface NONE. +3 KATs pin the three-way ladder dispatch by job targets (23/23).
frstrtr
added a commit
that referenced
this pull request
Jun 21, 2026
…ssify->dispatch) [#82 leg-2 / Stage 4d] (#297) Replace the Stage-4a mining_submit stub with the live hot path. Reconstruct the 80-byte DGB block header from the JobSnapshot + miner inputs (coinbase = coinb1||en1||en2||coinb2; merkle ascent from the coinbase txid; header = version|prev|merkle|ntime|nbits|nonce, all little-endian / prevhash reversed to internal order), run the DGB-Scrypt PoW digest through the #286 scrypt_pow SSOT, expand both compact targets via compact_to_target, and classify via the Stage-4d submit_classify SSOT (tighten-first): WonBlock -> serialize the full block (BIP144 coinbase witness when segwit active) and hand it to the dual-path broadcaster submit_block_fn (P2P relay + submitblock RPC fallback, #82); scream-never-drop on a won block that reaches no sink. ShareAccept -> forward the found-share fields to try_mint_share (the #295 producer seam -> #294 mint bind); degrades to accepted-without- credit when no mint fn is wired (no silent drop). Reject -> stratum low-difficulty error. work_source.cpp / work_source_test.cpp only; per-coin isolation held. The header layout is byte-for-byte Bitcoin (only the PoW digest differs, Scrypt); no share format, coinbase commitment, or PPLNS math touched -> p2pool-merged-v36 surface NONE. +3 KATs pin the three-way ladder dispatch by job targets (23/23). Co-authored-by: frstrtr <frstrtr@users.noreply.github.com>
frstrtr
added a commit
that referenced
this pull request
Jun 23, 2026
grind_won_nonce(header80, target) increments the 80-byte header nonce [76..79] LE until scrypt_pow_hash(header) <= target -- the EXACT header_chain.hpp satisfaction gate -- calling THROUGH the #286 digest CALL SSOT (never a bypass hash), so a nonce it accepts is one node B ACCEPTs. This is the missing primitive between the faithful won-block reconstruction and a ProcessNewBlock ACCEPT: the leg-2 A/B delivery proof reached node B but was consensus-rejected high-hash precisely because the forced-won seam carried no real PoW. Fails closed: returns nullopt when no nonce satisfies inside the budget (or the full 2^32 space wraps) -- a header that does not satisfy its target is never broadcast, mirroring the reconstructor loud-throw. dgb_nonce_grinder_test (5/5): finds a satisfying nonce well inside budget, the winning header satisfies the gate and its reported digest == the SSOT digest, the winning nonce is written LE into [76..79], re-grinding from the winner succeeds on iter 1, and an unsatisfiable target exhausts the budget to nullopt. Reuses the _dgb_scrypt_tus real-scrypt set; header-only u256, no core / no dgb OBJECT lib. Added to both build.yml --target allowlists. Fenced src/impl/dgb/ + build.yml. Wiring grind -> reconstruct -> submit on the live forced-won path and the node-B ACCEPT gate proof are the explicitly-next integration slice.
frstrtr
added a commit
that referenced
this pull request
Jun 23, 2026
…KAT)
regrind_block_nonce: grind the header nonce of an ALREADY-FRAMED
reconstructed-block blob (reconstruct_won_block_from_template {bytes})
until its DGB-Scrypt PoW digest satisfies the parent target, writing the
winning nonce back into header [76..79] IN PLACE. The missing wiring
between the faithful won-block reconstruction (merkle root fixed) and a
node-B ProcessNewBlock ACCEPT: the A/B delivery proof reached node B but
was consensus-rejected "high-hash" because the forced-won seam carried
no real PoW.
Ordering invariant enforced structurally: runs only on an already-framed
block (merkle root set FIRST by reconstruct), mutates ONLY header bytes
[76..79], never the merkle region [36..67] or tx tail. Hash via the #286
scrypt_pow_hash SSOT only; satisfaction = the exact pow <= target gate
header_chain.hpp runs. Fail-closed (nullopt, bytes UNCHANGED) on a runt
blob or exhausted budget.
KAT 5/5: reground header satisfies target via SSOT; only [76..79] mutate
(merkle + tx tail byte-preserved); runt-blob fail-closed; exhausted-budget
fail-closed; deterministic. Reuses the _dgb_scrypt_tus real-scrypt set;
header-only, no core / no OBJECT lib. Both build.yml --target allowlists.
Per-coin isolation: src/impl/dgb/ only. p2pool-merged-v36 surface: NONE.
frstrtr
added a commit
that referenced
this pull request
Jun 23, 2026
dgb(#82 4b/4c): scrypt_pow.hpp digest CALL SSOT + satisfaction-gate KAT
frstrtr
added a commit
that referenced
this pull request
Jun 23, 2026
The missing composition between leg-2's faithful won-block reconstruction and a node-B ProcessNewBlock ACCEPT. finalize_won_block_pow takes a reconstructed block (header[0..79] with merkle_root already set -- merkle FIRST, integrator-pinned ordering) and grinds the nonce at [76..79] THROUGH grind_won_nonce -> scrypt_pow_hash (the #286 digest CALL SSOT) until the DGB-Scrypt PoW satisfies the parent target, splices the winning nonce back, and regenerates the RPC-fallback hex in lockstep with the P2P-arm bytes. This closes the "high-hash, proof of work failed" rejection: the forced-won seam reached node B but carried no real PoW. SSOT call-through, never a bypass hash -- a finalized block is by construction one node B's own Scrypt validation accepts. Fail-closed (nullopt) on sub-80-byte input or no-nonce-in-budget, mirroring make_reconstruct_closure's never-a-partial-block posture. Standalone-guard discipline: depends ONLY on nonce_grinder.hpp (real btclibs scrypt + header-only u256); no core, no dgb OBJECT lib, no util/HexStr (local lowercase encoder, byte-identical to HexStr). Test links the SAME _dgb_scrypt_tus set as dgb_nonce_grinder_test. +5 KATs (dgb_won_block_finalize_test, 5/5 green): finalized header pow<=target via the same SSOT; winning nonce spliced LE into [76..79]; hex == bytes; ONLY the 4 nonce bytes mutate (merkle + tx tail untouched); fail-closed on a 79-byte input. Registered in BOTH build.yml --target allowlists (#143 trap). Fenced: src/impl/dgb/** + build.yml allowlist only. p2pool-merged-v36 surface: NONE. DGB-Scrypt standalone parent in the V36 default build.
frstrtr
added a commit
that referenced
this pull request
Jun 23, 2026
…ssify->dispatch) [#82 leg-2 / Stage 4d] (#297) Replace the Stage-4a mining_submit stub with the live hot path. Reconstruct the 80-byte DGB block header from the JobSnapshot + miner inputs (coinbase = coinb1||en1||en2||coinb2; merkle ascent from the coinbase txid; header = version|prev|merkle|ntime|nbits|nonce, all little-endian / prevhash reversed to internal order), run the DGB-Scrypt PoW digest through the #286 scrypt_pow SSOT, expand both compact targets via compact_to_target, and classify via the Stage-4d submit_classify SSOT (tighten-first): WonBlock -> serialize the full block (BIP144 coinbase witness when segwit active) and hand it to the dual-path broadcaster submit_block_fn (P2P relay + submitblock RPC fallback, #82); scream-never-drop on a won block that reaches no sink. ShareAccept -> forward the found-share fields to try_mint_share (the #295 producer seam -> #294 mint bind); degrades to accepted-without- credit when no mint fn is wired (no silent drop). Reject -> stratum low-difficulty error. work_source.cpp / work_source_test.cpp only; per-coin isolation held. The header layout is byte-for-byte Bitcoin (only the PoW digest differs, Scrypt); no share format, coinbase commitment, or PPLNS math touched -> p2pool-merged-v36 surface NONE. +3 KATs pin the three-way ladder dispatch by job targets (23/23). Co-authored-by: frstrtr <frstrtr@users.noreply.github.com>
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.
Stage 4b/4c — embedded real work-gen, foundational slice. First piece of the ACCEPT pillar under #82 (won block reaches AND is accepted by the network).
What
src/impl/dgb/coin/scrypt_pow.hpp— fenced SSOT wrapping btclibsscrypt_1024_1_1_256(80-byte header), decoding the 32-byte digest via the existingu256::from_le_bytes(dgb_arith256.hpp). Closes the documented "the scrypt CALL itself lands at the ingest boundary in a following slice" TODO.Why this slice
The nonce grinder (next slice) needs a real
scrypt(header) <= targetprimitive to find a valid-PoW nonce; grinder → reconstruct-with-valid-PoW → node-B ACCEPT is the path to the integrator tip-extension bar. This is the digest floor under that.Test — dgb_scrypt_pow_test (5/5 green)
DigestMatchesPinnedVector— scrypt bytes over a fixed header pinned (vector from btclibs scrypt itself, the DGB-Scrypt algo SSOT).PointerAndArrayOverloadsAgree,SatisfiesEqualTarget.SatisfiesTargetJustAbove/FailsTargetJustBelow— proves the LE decode compares correctly against SetCompact targets the way header_chain.hpp satisfaction gate does (pow_hash <= target, MSB-first).Scope / isolation
src/impl/dgb/**+ both build.yml--targetallowlist blocks. No shared base touched — scrypt.cpp is compiled directly into the test (consumed, not modified), mirroring header_chain_test.End-to-end agreement with DigiByte Core is proven by the live node-B ACCEPT test (4b/4c bar), not this unit KAT.
HOLD merge — integrator merges with operator push approval.