Skip to content

nmc(underfill): port near-empty-template guard to NMC template_builder (+ KAT)#729

Merged
frstrtr merged 2 commits into
masterfrom
fix/nmc-underfill-guard
Jul 17, 2026
Merged

nmc(underfill): port near-empty-template guard to NMC template_builder (+ KAT)#729
frstrtr merged 2 commits into
masterfrom
fix/nmc-underfill-guard

Conversation

@frstrtr

@frstrtr frstrtr commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Ports the block-underfill guard to the NMC (Namecoin) coin module, matching the LTC/DOGE/DASH/BTC implementation. SAFE-ADDITIVE, log-only — no consensus or wire bytes changed; the template path is byte-identical when the guard does not trip.

What

  • src/impl/nmc/coin/template_builder.hpp

    • UNDERFILL_MIN_FILL_BYTES = 50'000 / UNDERFILL_BACKLOG_SLACK = 50'000 — the v36-native cross-coin thresholds pinned to the legacy p2pool near-empty floor (~50 kB), identical to LTC/DOGE/DASH/BTC.
    • Pure underfill_guard_trips(selected_bytes, mempool_bytes, mempool_known_fees) predicate (near_empty && has_backlog), exact same shape as the BTC port / DASH free-predicate form.
    • Guard wired where selected txs are finalized into the template: selected_bytes accumulated in the existing pack() loop, then evaluated against the REAL Mempool::byte_size() / total_fees(); emits a [EMB-NMC] TemplateBuilder UNDERFILL WARNING when tripped. Never blocks work, never alters the template.
    • SAFE-ADDITIVE trailing bool* underfill_tripped = nullptr observation seam — every existing caller unchanged; the KAT pins wiring without a log scraper.
  • src/impl/nmc/test/nmc_underfill_guard_test.cpp — KAT mirroring test_btc_underfill_guard.cpp / test_dash_underfill_guard.cpp:

    • predicate pins: thresholds match the cross-coin values; near-empty + fee-paying backlog trips; empty mempool never trips; fee-unknown backlog never trips; floor and slack boundaries strict.
    • build_template wiring: (a) near-empty + backlog trips through the genuine stale-input-guard selection-empty path; (b) near-empty + NO backlog (empty mempool, and a fully drained small pool) does NOT trip; (c) filled/selected template does NOT trip — GBT projection asserted unchanged when tripped, plus a default-seam parity test.

Test registration (deviation from the sibling ports — deliberate)

The KAT compiles INTO the existing allowlisted nmc_template_builder_test target as a second source (gtest_add_tests ... AUTO scans all target sources), rather than as a standalone nmc_underfill_guard_test target. Reason: adding a new target requires the matching build.yml --target allowlist edit (else CTest reds master with a NOT_BUILT sentinel — the #724/#728 lesson), and the push credential here has no workflow scope, so build.yml cannot be touched from this branch. Folding into the already-allowlisted target satisfies the same invariant with zero workflow edits. If a standalone target is preferred for symmetry with test_btc_underfill_guard / test_dash_underfill_guard, it is a two-line follow-up by someone with workflow scope.

Verification

Local: all 28 tests in the combined nmc_template_builder_test binary pass (17 pre-existing + 11 new NmcUnderfillGuard KATs); the WARNING fires exactly and only in the trip case.

Severity note

NMC is BTC's merge-mined aux child — a near-empty namecoin aux block does not waste parent PoW, so severity is LOW. This port completes the all-coin underfill matrix (LTC/DOGE/DASH/BTC/DGB/BCH/NMC).

frstrtr and others added 2 commits July 17, 2026 19:53
…r (+ KAT)

Port of the LTC/DOGE near-empty-template guard (DASH free-predicate form,
same shape as the BTC port) to the NMC embedded template path:

* src/impl/nmc/coin/template_builder.hpp: UNDERFILL_MIN_FILL_BYTES /
  UNDERFILL_BACKLOG_SLACK pinned at the cross-coin 50 kB legacy p2pool
  near-empty floor; pure underfill_guard_trips() predicate; guard wired
  where selected txs are finalized (selected_bytes accumulated in the
  existing pack() loop). LOG-ONLY (WARNING) — never mutates the template,
  never blocks work. SAFE-ADDITIVE trailing bool* underfill_tripped seam
  (defaulted nullptr; every existing caller byte-for-byte unchanged).

* src/impl/nmc/test/nmc_underfill_guard_test.cpp: KAT mirroring
  test_btc_underfill_guard.cpp — predicate pins at thresholds/boundaries
  plus build_template wiring: (a) near-empty + fee-paying backlog trips
  (via the genuine stale-input-guard selection-empty path), (b) empty
  mempool / drained small pool never trip, (c) filled template never
  trips; GBT projection asserted unchanged when tripped; default-seam
  parity test.

* src/impl/nmc/test/CMakeLists.txt: the KAT compiles INTO the existing
  allowlisted nmc_template_builder_test target (second source;
  gtest_add_tests AUTO scans all target sources), so the build.yml
  --target allowlist needs NO edit — a new target absent from that
  allowlist reds master as a NOT_BUILT sentinel (the #724/#728 lesson).

NMC is BTC's merge-mined aux child, so a near-empty aux block does not
waste parent PoW (severity LOW); this completes the all-coin underfill
matrix. No consensus or wire bytes changed.
…rget + build.yml allowlist

Mirror btc/dash/dgb *_underfill_guard_test symmetry: the NMC underfill guard
KAT was compiled into the allowlisted nmc_template_builder_test target to dodge
the workflow-scope wall. Register it as its own nmc_underfill_guard_test CMake
target and add it to the build.yml ctest --target allowlist (both build blocks)
so the drift-guard stays green.
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