Skip to content

dash(daemonless): emit the self-derived MN checkpoint from the MN-CKPT bridge (task #154) - #1294

Draft
frstrtr wants to merge 1 commit into
integrator/dashd-cut-header-backfill-canservefrom
integrator/dashd-cut-bridge-checkpoint-dump
Draft

dash(daemonless): emit the self-derived MN checkpoint from the MN-CKPT bridge (task #154)#1294
frstrtr wants to merge 1 commit into
integrator/dashd-cut-header-backfill-canservefrom
integrator/dashd-cut-bridge-checkpoint-dump

Conversation

@frstrtr

@frstrtr frstrtr commented Aug 20, 2026

Copy link
Copy Markdown
Owner

What

Give the MN-CKPT bridge the one-shot --dump-mn-checkpoint seam that until now
lived only on the empty-DIP3 replay-fold consumer. This lets a fresh anchor be
bumped from the baked checkpoint via a short forward fold (bridge SEEDs the baked
2513000 checkpoint and forward-applies to H), instead of a from-DIP3 replay (~a day).

Reward-safe: no change to the fold / apply / consensus path — only a dump hook and
a serialization overload.

The change (3 parts, each mirroring existing code)

  1. mn_checkpoint_dump.hpp — factor the reward-safety-critical payload/.inc
    assembly out of emit_mn_checkpoint_dump() into finish_mn_checkpoint_dump()
    (byte format unchanged, now single-sourced so the two dumpers cannot diverge),
    and add a bridge overload of emit_mn_checkpoint_dump() / write_mn_checkpoint_inc()
    that serializes MnStateMachine::entries() (std::map<uint256, MNState>) via a pure
    MNState -> ReplayMNState field-copy. Reuses emit_mn_record_line() and the
    self-verify-through-parse_mn_checkpoint() guard VERBATIM — a set that fails its
    own self-parse is never written.
  2. mn_checkpoint_lane.hpp — add set_dump_hook(target_height, fn) + a one-shot
    maybe_fire_dump() fired from the same clean-fold event that feeds
    set_on_block_applied (both apply sites). It therefore only fires on a
    forward-contiguous, non-gapped, non-payee-desynced, non-empty fold. Exact analog of
    FoldReplayConsumer::set_dump_hook. Unset = no-op.
  3. main_dash.cpp — in the cold MN-CKPT bridge arm (the g_replay_fold_prestate.empty()
    branch), install the hook when --dump-mn-checkpoint is set, mirroring the replay-fold
    install; mutually exclusive by the prestate predicate. Block hash comes from OUR
    PoW-validated header chain.

getmnlistdiff is payout-stripped and cannot back a checkpoint — the bridge's
apply_block (dashd BuildNewListFromBlock parity) is the source, so every field is
self-derived from chain, no dashd.

Test evidence

  • Build: c2pool-dash, DASH + real-BLS recipe (C2POOL_DASH_BLS=ON), Release — clean.
  • Run (--run --embedded-mainnet --coin-p2p-discover --coin-p2p-peers 16 --web-port 0 --dump-mn-checkpoint 2522504 <out>, no --replay-bulk, no --replay-fold-prestate):
    • --dump-mn-checkpoint ARMED on the MN-CKPT BRIDGE — the new install fires.
    • Bridge SEEDs baked-2513000 (entries=2974) and folds forward with
      diverged=0 and payee_ok == applied throughout (reward-safe).
  • Oracle-verify against fleet mainnet dashd (protx list registered 1 2522504):
    pending the dump landing (see note).

Note on pacing

On the build host the fold to H=2522504 is pace-limited by coin-P2P peer
contention
from two co-resident full-history self-derive runs saturating the same
peer pool: each periodic getmnlistd fold-point stalls until the next mainnet tip
re-drives it (this base predates the on-demand-mnlist re-ask, #1292). It advances
reward-safely and lands the anchor, but in hours rather than minutes on a contended
host — an environment constraint, not a defect in this change. On an uncontended host
(or the combined onion base with the reduced-mismatch payee logic) it bumps in minutes.

Base / landing

Stacked on integrator/dashd-cut-header-backfill-canserve so the diff is exactly this
one commit. Intended to ride into the combined onion (#1293), which carries the same
dump feature + bridge and where the fold-consumer set_dump_hook install already lives.

DRAFT — reward-path, operator review. Do not merge / undraft.

…T bridge (task #154)

The --dump-mn-checkpoint dumper was wired only to the empty-DIP3 replay-fold
consumer (constructed under --replay-fold-prestate), so producing a fresh
anchor meant a full DIP3->tip fold (~a day). The MN-CKPT bridge already
reconstructs the payout-bearing MN set correctly by SEEDING from the baked
checkpoint and forward-applying block-by-block (apply_block == dashd
BuildNewListFromBlock parity) up to tip -- it just had no dump hook.

Give the bridge the same one-shot dump-at-height seam the replay-fold consumer
has, so a fresh anchor can be bumped from the baked checkpoint in a short
forward fold instead of a from-DIP3 replay. Reward-safe: no change to the
fold/apply/consensus path.

1. mn_checkpoint_dump.hpp: factor the reward-safety-critical payload/.inc
   assembly out of emit_mn_checkpoint_dump() into finish_mn_checkpoint_dump()
   (byte format unchanged, single-sourced) and add a bridge overload of
   emit_mn_checkpoint_dump()/write_mn_checkpoint_inc() that serializes
   MnStateMachine::entries() (std::map<uint256,MNState>) via a pure MNState->
   ReplayMNState field-copy. It reuses emit_mn_record_line() and the
   self-verify-through-parse_mn_checkpoint() guard VERBATIM: a set that fails
   its own self-parse is never written.

2. mn_checkpoint_lane.hpp: add set_dump_hook(target_height, fn) plus a one-shot
   maybe_fire_dump() fired from the SAME clean-fold event that feeds
   set_on_block_applied (both apply sites) -- so it only fires on a
   forward-contiguous, non-gapped, non-payee-desynced, non-empty fold. Exact
   analog of FoldReplayConsumer::set_dump_hook. Unset = no-op.

3. main_dash.cpp: in the cold MN-CKPT bridge arm (the g_replay_fold_prestate
   .empty() branch), install the hook when --dump-mn-checkpoint is set --
   mirroring the replay-fold consumer install, mutually exclusive by the
   prestate predicate. The block hash comes from OUR PoW-validated header chain.
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