Skip to content

dgb(#82 4b/4c): wire regrind seam into forced-won soak driver (--soak-regrind) [HOLD] - #287

Closed
frstrtr wants to merge 6 commits into
masterfrom
dgb/82-soak-regrind-wire
Closed

dgb(#82 4b/4c): wire regrind seam into forced-won soak driver (--soak-regrind) [HOLD]#287
frstrtr wants to merge 6 commits into
masterfrom
dgb/82-soak-regrind-wire

Conversation

@frstrtr

@frstrtr frstrtr commented Jun 21, 2026

Copy link
Copy Markdown
Owner

What

Wires the #286 grind->reconstruct->submit regrind seam into the run-loop forced-won soak driver behind a new operator-only flag --soak-regrind (default OFF; absent from every production path).

When set, the faithful template-reconstruct closure is wrapped: after the block is framed, regrind_block_nonce grinds header[76..79] until the DGB-Scrypt digest satisfies the block's own declared nBits (the exact target node B validates), then the hex is recomputed so BOTH broadcast arms (embedded P2P relay + submitblock fallback) carry the ground bytes. Merkle root + tx tail untouched.

Why

A forced-won soak share carries no real Scrypt work, so the reconstructed block is rejected high-hash by node B (the documented gate on the live A/B ACCEPT proof). #286 landed the grind seam as library + KAT; this lands it in main_dgb.cpp --run, closing the last gap to a node-B ACCEPT end to end.

Scope / safety

  • Single-file run-loop edit (src/c2pool/main_dgb.cpp), fenced to DGB.
  • --soak-regrind OFF by default -> zero production behaviour change; genuine pool-won shares already satisfy the parent target and are NEVER reground.
  • build EXIT=0, --selftest EXIT=0, --help advertises the flag.

Stacking

Stacks on #286 (regrind seam + scrypt_pow SSOT, integrator-approved UID1727) and the #282 soak harness (cherry-picked here). Land #286 first, then this.

HOLD merge — integrator merges with operator 'push approved'. Next: run live regtest A/B with --soak-regrind and capture the node-B ACCEPT.

frstrtr added 6 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.
Closes the #82 broadcaster dual-path gate on the wire: live UpdateTip won
block (regtest diff, no test-only seam) -> reconstruct coinbase-only ->
ARM A submit_block_p2p_raw relays to a peer node, asserting PROP1
(coinbase-only accepted, not fail-open) + PROP2/ARM-A (P2P reaches network).
Scripts-only, fenced (scripts/), DGB-isolated, localhost regtest, self-service
creds. Two live-leg items remain: digibyted self-provisioning (daemon-gated,
only namecoind on fleet) and ARM B submitblock-fallback isolation mechanism
(no --no-p2p-relay flag -> integrator design call), both explicit in-file.
Approved operator toggle (integrator UID1709, option a): suppress ONLY
the embedded P2P-relay arm in main_dgb on_block_found, leaving the
external-digibyted submitblock seam (RPC fallback) live. Lets the #82
regtest soak prove the submitblock fallback lands the won block on its
own, deterministically, instead of being masked by a silent or dead P2P
relay -- the historical #82 gap.

Additive, DGB-fenced (src/c2pool/main_dgb.cpp only); no consensus/share/
PPLNS/shared surface. Real operator flag, not a test-only seam (mirrors
the no-test-seam principle honored for ARM A).
…-regrind)

The forced-won soak reconstructs a block from an injected won share that
carries no real Scrypt work, so node B rejects it high-hash. --soak-regrind
(default OFF, absent from every prod path) wraps the faithful reconstruct
closure: after the version-agnostic template reconstruct frames the block, it
grinds header[76..79] via regrind_block_nonce until the DGB-Scrypt digest
satisfies the block's OWN declared nBits -- exactly the target node B
validates -- then recomputes the hex so both broadcast arms carry the ground
bytes. Merkle root and tx tail are untouched. This closes the last gap to a
live A/B node-B ACCEPT: the seam (PR #286) was a library + KAT; this lands it
in the run-loop behind an explicit operator-only flag.

build EXIT=0, --selftest EXIT=0, --help advertises --soak-regrind.
@frstrtr

frstrtr commented Jun 21, 2026

Copy link
Copy Markdown
Owner Author

Superseded by #291 (consolidated #82 gate PR). The soak substrate here (fa3a3ad/80e8f30e6) is already on master via #282; the --soak-regrind seam (cdc52f7) is subsumed by #291s grind->reconstruct->submit JOINT in won_block_finalize.hpp. Branch preserved (not deleted). #82 lands via #291.

@frstrtr frstrtr closed this Jun 21, 2026
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