Skip to content

dash(embedded): pin the mainnet masternode-set anchor at height 2513000 — the last thing blocking daemonless cold start - #972

Merged
frstrtr merged 1 commit into
masterfrom
dash/pin-mn-checkpoint-mainnet
Jul 30, 2026
Merged

dash(embedded): pin the mainnet masternode-set anchor at height 2513000 — the last thing blocking daemonless cold start#972
frstrtr merged 1 commit into
masterfrom
dash/pin-mn-checkpoint-mainnet

Conversation

@frstrtr

@frstrtr frstrtr commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Follows #956 (the generator). One generated file; no code changes.

Why this was blocking

The daemonless embedded arm cold-starts its payout-bearing masternode set from a release-pinned checkpoint. That set cannot be obtained over P2P — the Simplified MN List omits scriptPayout and nLastPaidHeight, and neither is committed in merkleRootMNList. So the checkpoint is not a workaround, it is inherent to the protocol.

No anchor had ever been pinned. The shipped .inc was a 999-byte placeholder and the runtime refused it:

gen_mn_checkpoint: REFUSED: UNPINNED: this build carries no masternode-set anchor

Correct fail-closed behaviour — and also why daemonless cold start could not work at all.

The anchor

network    mainnet
height     2513000
blockhash  000000000000002114d621d90f28b52c07746414491cbffc7cd373b3a56bc950
count      2068 masternodes
digest     dc34d0fb112dd2d509dcc7837e308d5444bd1390a712db708a276f3911e3e16f
generated  2026-07-30T00:17:53Z
source     dashd protx list valid true 2513000 (Dash Core 23.1.7)

2087 lines, 828 KB.

Provenance and integrity

Produced offline with tools/dash/gen_mn_checkpoint.py from a captured protx list valid true array, so no RPC credentials were involved. The capture was integrity-checked across transfer — 2068 entries, 2970603 bytes, matching byte counts at both ends.

Height 2513000 was 204 blocks behind the tip at capture, deep enough to be settled.

gen_mn_checkpoint.py verify on the written file:

OK  src/impl/dash/coin/checkpoints/dash_mn_checkpoint_mainnet.inc
    network=mainnet height=2513000 count=2068
    digest=dc34d0fb...e16f (recomputed, matches)

SPDX AGPL-3.0-or-later present; file marked GENERATED FILE -- DO NOT EDIT BY HAND.

Acceptance — deliberately not "CI is green"

Green CI proves the parser accepts the format. It does not prove daemonless cold start works.

The real gate: a node built from this, started with --embedded-mainnet and no coin-RPC configured, must leave the CHECKPOINT REFUSED state and build a template. That has not been demonstrated and is the next step. I would rather state that plainly than let a green tick imply more than it covers — the "armed but never exercised" pattern has cost this project three separate false milestones (#940, #952, #963).

Reward safety

Does not change share bytes, coinbase construction, or payout weighting. It supplies the MN set the embedded arm uses when building a DIP4 coinbase; a wrong anchor would fail closed at the per-template viability gates rather than produce a bad payee. Production nodes remain on arm=dashd-fallback and are unaffected by this file until --embedded-mainnet is deliberately enabled.

The daemonless embedded arm cold-starts its payout-bearing masternode set
from a release-pinned checkpoint, because that set is not obtainable over
P2P: the Simplified MN List omits scriptPayout and nLastPaidHeight, and
neither is committed in merkleRootMNList. Until now no anchor had ever
been pinned, so the shipped .inc was a placeholder and the runtime
refused it:

  gen_mn_checkpoint: REFUSED: UNPINNED: this build carries no
  masternode-set anchor

That refusal is correct behaviour and it is also why daemonless cold
start could not work at all.

Anchor:

  network    mainnet
  height     2513000
  blockhash  000000000000002114d621d90f28b52c07746414491cbffc7cd373b3a56bc950
  count      2068 masternodes
  digest     dc34d0fb112dd2d509dcc7837e308d5444bd1390a712db708a276f3911e3e16f
  generated  2026-07-30T00:17:53Z
  source     dashd protx list valid true 2513000 (Dash Core 23.1.7)

Produced offline with tools/dash/gen_mn_checkpoint.py from a captured
`protx list valid true` array, so no RPC credentials were involved in
generating it. The capture was verified end to end before pinning: 2068
entries, 2970603 bytes, byte counts matched across transfer.

The height is 204 blocks behind the tip at capture time, deep enough to
be settled. The tool's own verify pass re-derives the digest from the
written file and confirms every structural rule the runtime parser
enforces; it reports OK with the digest matching.

Acceptance for this change is NOT that CI is green. It is that a node
built from it, started with --embedded-mainnet and no coin-RPC
configured, leaves the CHECKPOINT REFUSED state and builds a template.
That has not been demonstrated yet and is the next step.
@frstrtr
frstrtr merged commit 6f881d3 into master Jul 30, 2026
29 checks passed
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