Skip to content

dash: self-derived MN-set checkpoint dump (--dump-mn-checkpoint H FILE) - #1268

Closed
frstrtr wants to merge 1 commit into
dash/mn-diff-store-straddle-memberset-assemblefrom
dash/mn-checkpoint-dump-self-derived
Closed

dash: self-derived MN-set checkpoint dump (--dump-mn-checkpoint H FILE)#1268
frstrtr wants to merge 1 commit into
dash/mn-diff-store-straddle-memberset-assemblefrom
dash/mn-checkpoint-dump-self-derived

Conversation

@frstrtr

@frstrtr frstrtr commented Aug 17, 2026

Copy link
Copy Markdown
Owner

Self-derived MN-set checkpoint DUMP (--dump-mn-checkpoint H FILE)

DRAFT — do not merge. Stacked on #1267 (dash/mn-diff-store-straddle-memberset-assemble). DASHD-CUT, operator decision 2026-08-17.

What this adds

A capability to serialize the --replay-bulk DML fold's REGISTERED masternode set at a target height H to the checkpoint .inc payload format (mn_checkpoint.hpp), self-derived from the fold's own root-checked state — no dashd RPC, no trusted protx list snapshot. scriptPayout is taken verbatim from the ProRegTx/ProUpRegTx the fold replayed; nLastPaidHeight from the payee bookkeeping the fold already keeps (dashd BuildNewListFromBlock parity). This is the emitter the operator's decision requires: the two fields not on the DIP-4 wire and not committed in merkleRootMNList come from the chain-replayed fold, not from a snapshot dashd never consumes.

Reward-safety is by REUSE, not new code

  • 17-field order + conversions are the same the runtime parser reads (mn_checkpoint.hpp) and gen_mn_checkpoint.py writes.
  • Digest is the shared mn_checkpoint_digest().
  • write_mn_checkpoint_inc() re-parses its own output through parse_mn_checkpoint() (with the engine's network) before writing — it can never emit a file the runtime cold-start would refuse.
  • REGISTERED, not valid-filtered: PoSe-banned MNs are emitted carrying poseBanHeight; isValid is re-derived as poseBanHeight==0.
  • Load-bearing byte-order split preserved: proTxHash/collateralHash via GetHex (display), keyIDOwner/keyIDVoting via forward LE-limb bytes (matching hex_to_uint160), and lines sorted by proTxHash display hex (matching the generator, NOT std::map internal order).
  • Serve-inert: only reads the engine and writes one file; fires exactly once, after the successful fold whose cursor first reaches H (the fold's own per-block merkleRootMNList self-check is the safety net — a diverged/poisoned fold never reaches the dump).

Files

  • new src/impl/dash/coin/mn_checkpoint_dump.hppemit_mn_checkpoint_dump / emit_mn_record_line / write_mn_checkpoint_inc
  • src/impl/dash/coin/replay_fold_consumer.hpp — one-shot set_dump_hook(H, fn), separate from the W4 post_fold seam so both coexist
  • src/c2pool/main_dash.cpp--dump-mn-checkpoint H FILE arms the hook on the --replay-fold consumer path; the source line names the self-derived provenance
  • test/test_dash_mn_checkpoint.cppDashMnCheckpointDump round-trip KAT: a replayed set dumps and parses back field-identical through parse_mn_checkpoint() (the replay-dumped analog of CheckpointSetIsFieldIdenticalToRpcSeed), plus sort-order, determinism, digest, .inc file, and fail-closed (empty / payee-less) cases

Verification (vm905, C2POOL_DASH_BLS=REAL, dashd ABSENT)

  • KATs green: DashMnCheckpointDump.ReplayDumpedSetRoundTripsFieldIdenticalToParser, DashMnCheckpointDump.EmptyEngineAndPayeelessRefuse.
  • Full checkpoint test target test_dash_node_reception_wire: 173/173 passed.
  • c2pool-dash binary builds; runtime banner DASH BLS backend: REAL; --dump-mn-checkpoint H FILE present in usage.

How the integrator runs the long detached self-derive

The dump fires at H for any --replay-fold run that reaches H. The full DIP3→H replay (~1.49M blocks) is not run in-agent. See the workflow report for the exact background command, resume/capture dir, and the one remaining enabling note (a from-empty-DIP3 cold seed is separate arming infrastructure the prestate loader does not yet supply).

Serialize a --replay-bulk DML fold's REGISTERED masternode set at a
target height H to the checkpoint .inc payload (mn_checkpoint.hpp),
SELF-DERIVED from the fold's own root-checked ReplayMNState -- no dashd
RPC, no trusted protx snapshot (operator decision 2026-08-17).
scriptPayout is taken verbatim from the ProRegTx/ProUpRegTx the fold
replayed; nLastPaidHeight from the payee bookkeeping the fold already
keeps (dashd BuildNewListFromBlock parity).

Reward-safety is by REUSE: the 17-field order + conversions are the same
the runtime parser reads and gen_mn_checkpoint.py writes; the digest is
the shared mn_checkpoint_digest(); write_mn_checkpoint_inc() re-parses its
own output through parse_mn_checkpoint() before writing, so it can never
emit a file the runtime cold-start would refuse. REGISTERED, not valid-
filtered: PoSe-banned MNs are emitted carrying poseBanHeight (isValid is
re-derived as poseBanHeight==0). Load-bearing byte-order split preserved:
proTxHash/collateralHash via GetHex (display), keyIDOwner/keyIDVoting via
forward LE-limb bytes (matching hex_to_uint160), lines sorted by proTxHash
display hex (matching the generator, NOT std::map internal order).

- new src/impl/dash/coin/mn_checkpoint_dump.hpp: emit_mn_checkpoint_dump /
  emit_mn_record_line / write_mn_checkpoint_inc
- replay_fold_consumer.hpp: one-shot set_dump_hook(H, fn), fired after the
  successful fold whose cursor first reaches H (separate from the W4
  post_fold seam so both coexist)
- main_dash.cpp: --dump-mn-checkpoint H FILE arms the hook on the
  --replay-fold consumer path; source line names the self-derived
  provenance
- test_dash_mn_checkpoint.cpp: DashMnCheckpointDump round-trip KAT --
  a replayed set dumps and parses back FIELD-IDENTICAL through
  parse_mn_checkpoint() (mirror of CheckpointSetIsFieldIdenticalToRpcSeed),
  plus sort-order, determinism, digest, .inc file, and fail-closed
  (empty / payee-less) cases

Build: C2POOL_DASH_BLS=REAL. 173/173 in the checkpoint test target green.
@frstrtr

frstrtr commented Aug 20, 2026

Copy link
Copy Markdown
Owner Author

Superseded by #1293 (combined fetch+fold onion). This branch's head commit is present in #1293 by exact SHA (verified via triage). Closing to reconcile the draft backlog; the branch is preserved (not deleted) — reopen if #1293 changes course.

@frstrtr frstrtr closed this Aug 20, 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