Skip to content

dgb: M3 §7b DigiShield Scrypt-only retarget (rebased on master@064a717d) - #153

Merged
frstrtr merged 8 commits into
masterfrom
dgb/m3-scrypt-window-walk
Jun 18, 2026
Merged

dgb: M3 §7b DigiShield Scrypt-only retarget (rebased on master@064a717d)#153
frstrtr merged 8 commits into
masterfrom
dgb/m3-scrypt-window-walk

Conversation

@frstrtr

@frstrtr frstrtr commented Jun 18, 2026

Copy link
Copy Markdown
Owner

§7b — DigiShield Scrypt-only retarget (DGB single-coin)

Rebased onto master@064a717d (post #150/#151/#152 merges). Five GPG-signed commits, zero conflict drift from the three landed branches.

Commits (bottom -> top)

  • 98bf557f DigiShield Scrypt-only ancestor walk + work-credit predicate (dgb_digishield.hpp SSOT)
  • 25822a5c HeaderChain Scrypt-only validate() body + retarget-window over Scrypt samples only
  • 587d9f19 per-algo DigiShield damped retarget multiply (v3 damped = nominal + (actual-nominal)/8, clamp [3/4, 3/2])
  • f524643a wire DigiShield next-target into HeaderChain ingest gate (nBits-style exact-match)
  • ca21fdd1 damped multiply at true 256-bit width (dgb_arith256.hpp, mul-then-div = DGB Core order)

Scope guardrails

Verification

  • build EXIT=0
  • digishield_walk_test 6/6 PASS
  • header_chain_test 18/18 PASS (incl 5 DigiShield256 >2^64 / 256-bit-truncation boundary vectors + continuity-skip acceptance)

frstrtr added 8 commits June 18, 2026 10:28
Isolates the consensus quirk flagged at header_chain.hpp DIGISHIELD INSERTION
POINT: the Scrypt difficulty window must walk Scrypt-algo ancestors ONLY and
skip continuity (non-Scrypt) headers; folding a continuity header into the
window corrupts the Scrypt retarget and breaks the THIRD INVARIANT work-
neutrality. Adds header_credits_work() as the single SSOT predicate the
validate() work-accounting and the retarget walk both consult, so they cannot
drift. Header-only (deps: dgb_block_algo.hpp + std), so it links into the
standalone GTest guard with no dgb OBJECT lib.

- coin/dgb_digishield.hpp: scrypt_window_ancestors(), header_credits_work()
- test/digishield_walk_test.cpp: 6 guards (zero-bits Scrypt, interleave skip,
  leading-continuity run, exhausted chain, zero window, work predicate)
- wired into BOTH ctest foreach AND both build.yml --target allowlists (#143)

Per-algo DigiShield target math layers on top in the following slice.
Replace the header_chain.hpp namespace stub with the validate() body that
drives the Scrypt-only chain: per-header disposition (Scrypt validate /
accept-by-continuity / reject), work-neutral accounting, and the Scrypt-only
DigiShield retarget-window assembly (averaged target + actual timespan).

Work-neutrality SSOT: cumulative work advances iff header_credits_work(), the
same predicate scrypt_window_ancestors() consults for the retarget window, so
the work-accounting and retarget paths cannot drift. Continuity headers extend
the chain but credit zero work and are excluded from the retarget window.

THIRD INVARIANT under test: a continuity header inside the nominal window is
proven skipped from both avg_target and actual_timespan (a naive all-headers
window would corrupt both). The damped DigiShield/MultiShield arith_uint256
multiply layers on RetargetWindow in the following slice.

Guard header_chain_test wired into the ctest foreach AND both build.yml
--target allowlists (the #143 NOT_BUILT lesson). 6/6 PASS, build EXIT=0.
digishield_next_target() + DigiShieldParams in coin/header_chain.hpp:
consumes the Scrypt-only RetargetWindow (avg_target + actual_timespan over
Scrypt ancestors only) and produces the next expanded target via DigiByte
DigiShield v3: amplitude filter damped = nominal + (actual-nominal)/8, clamp
to [3/4, 3/2] nominal rails, bnNew = avg*damped/nominal, capped to pow_limit.
__int128 intermediate (proxy-overflow safe); arith_uint256 swaps in later with
the same field shape. Returns 0 on empty window / degenerate nominal so the
caller keeps the prior target.

header_chain_test: +6 DigiShield cases -- nominal (target unchanged), both
clamp rails (ceiling 3/2, floor 3/4 via negative timespan), pow_limit floor,
empty-window/zero-nominal safety, and end-to-end over the live continuity-
skipped window. 12/12 pass, build EXIT=0. Header-only; reuses the already-
wired header_chain_test guard (no new ctest/build.yml target).
validate_and_append now enforces the DigiShield-computed next target on the
VALIDATE_SCRYPT path: the declared Scrypt target must EQUAL the next-target
computed over the Scrypt-only retarget window ending at the current tip
(assembled before the header is appended), the nBits-style consensus rule.

A configured HeaderChain(DigiShieldParams, window) arms the gate; a default-
constructed chain leaves target_timespan 0 so digishield_next_target() returns
the 0 sentinel and the gate is a no-op (existing retarget/work-accounting
tests run unconstrained, unchanged). A rejected header never mutates the chain
(size + cumulative work preserved).

+1 ingest-gate test vector (window 1, deterministic 7/8 next-target): wrong
target REJECTED with chain unchanged, exact target VALIDATED_SCRYPT crediting
work, continuity header bypasses the gate. Added INTO header_chain_test (no new
gtest target -> #143 NOT_BUILT trap avoided). 13/13 PASS, build EXIT=0.
Swap the uint64/__int128 retarget intermediate for a header-only 256-bit
unsigned (coin/dgb_arith256.hpp) reproducing arith_uint256 multiply-then-
divide with 256-bit overflow truncation -- the consensus arithmetic of
DigiByte Core CalculateNextWorkRequired. For uint64-range avg_target the
path is bit-identical to the prior intermediate, so the existing 13
vectors are unchanged; +5 boundary vectors prove the divergence above
2^64 and the 256-bit truncation near pow_limit that an __int128 proxy
could not reproduce. Header-only, single-coin (src/impl/dgb only), tests
added into header_chain_test (no new gtest target).
VALIDATE_SCRYPT path now rejects a declared Scrypt target EASIER than
pow_limit (target > pow_limit), mirroring DigiByte Core CheckProofOfWork.
This fires on the bootstrap/empty-window path (expected == 0) where the
nBits-style retarget-equality gate is a no-op, closing the hole where a
sub-minimum-difficulty header could seed/extend the chain during a stall.
pow_limit == 0 keeps the gate unconfigured (legacy default-ctor chains
unconstrained). +1 vector folded into header_chain_test (no new gtest
target; #143 NOT_BUILT trap avoided). 19/19 PASS, build EXIT=0.
CheckProofOfWork second half: the VALIDATE_SCRYPT path now rejects a
header whose scrypt(header) digest exceeds its declared target
(hash > target). Half 1 (target <= pow_limit) already landed; this
closes the missing PoW-satisfaction guard that was a placeholder.

HeaderSample gains a uint64 pow_hash proxy (mirrors ltc coin/header_chain
hash field). Context-free check, run after the pow_limit ceiling and
before the contextual nBits-equality gate, mirroring DigiByte Core
if (UintToArith256(hash) > bnTarget) return false. pow_hash == 0 is the
standalone default (trivially satisfies any target) so every existing
vector is unchanged; the embedded-daemon port fills the real digest into
the same field shape.

+1 vector folded INTO header_chain_test (no new gtest target, #143 trap
avoided): rejects pow_hash > target, accepts == and < boundary, and
confirms a continuity header short-circuits before the PoW check.
header_chain_test 20/20 PASS, build EXIT=0.
…u256)

Swap HeaderSample::target/pow_hash, RetargetWindow::avg_target,
DigiShieldParams::pow_limit and the digishield_next_target() return from
uint64 proxies to the full-width u256 (coin/dgb_arith256.hpp). An implicit
uint64 widening ctor keeps every uint64-range vector byte-identical, so the
ingest PoW-satisfaction + minimum-difficulty ceiling checks and the
DigiShield averaging now run at true arith_uint256 width through
validate_and_append. Adds u256 operator+= for the window target-sum average.

+1 ingest-path boundary vector folded into header_chain_test (no new gtest
target): a >2^64 target/digest decides acceptance the same way arith_uint256
would and diverges from a low64-only proxy in both directions. 21/21 PASS.

Confined to src/impl/dgb/; no shared base / bitcoin_family / CMake / build.yml
touch.
@frstrtr
frstrtr merged commit 81fef6a into master Jun 18, 2026
17 checks passed
frstrtr added a commit that referenced this pull request Jun 19, 2026
dgb: M3 §7b scrypt-digest conversion + retarget no-op + MTP guard (tail, rebased on master post-#153)
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