Skip to content

dgb(#82 4b/4c): scrypt_pow.hpp digest CALL SSOT + satisfaction-gate KAT - #286

Merged
frstrtr merged 3 commits into
masterfrom
dgb/82-4bc-scrypt-pow-ssot
Jun 21, 2026
Merged

dgb(#82 4b/4c): scrypt_pow.hpp digest CALL SSOT + satisfaction-gate KAT#286
frstrtr merged 3 commits into
masterfrom
dgb/82-4bc-scrypt-pow-ssot

Conversation

@frstrtr

@frstrtr frstrtr commented Jun 21, 2026

Copy link
Copy Markdown
Owner

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

  • New src/impl/dgb/coin/scrypt_pow.hpp — fenced SSOT wrapping btclibs scrypt_1024_1_1_256(80-byte header), decoding the 32-byte digest via the existing u256::from_le_bytes (dgb_arith256.hpp). Closes the documented "the scrypt CALL itself lands at the ingest boundary in a following slice" TODO.
  • One digest SSOT so the upcoming nonce grinder and the header_chain ingest boundary can never disagree on PoW byte order.

Why this slice

The nonce grinder (next slice) needs a real scrypt(header) <= target primitive 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

  • DGB-only: src/impl/dgb/** + both build.yml --target allowlist blocks. No shared base touched — scrypt.cpp is compiled directly into the test (consumed, not modified), mirroring header_chain_test.
  • V36 Scrypt-only: the only PoW digest DGB validates.

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.

frstrtr added 3 commits June 21, 2026 02:29
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
frstrtr merged commit 13c9dae into master Jun 21, 2026
30 checks passed
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>
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