DC-MITHRIL-07
DC true enforced driftThe live --mode node FirstRun arm INVOKES the native Mithril bootstrap path (DC-MITHRIL-03 / S1b) from
live snapshot files -- it routes the verified Mithril manifest + the V2 LedgerDB state (S1a) + the
Stage-2 tables MemPack (S1c) + the Cardano Shelley genesis (the required metadata file) through the
UNCHANGED S1a/S1b/S1c native chain, with NO cardano-cli / JSON consensus-input bundle / operator seed on
this route; the verified snapshot IS the source. (a) ROUTE SELECTION: when --mithril-state-path AND
--mithril-tables-path are BOTH present, the FirstRun arm takes the native route
(first_run_native_mithril_bootstrap) -- which supersedes the legacy CLI-seed body; the two are NEVER a
fallback for one another. (b) THE WIRING (native_firstrun::native_first_run_bootstrap): read manifest
bytes -> import_mithril_manifest_from_bytes -> the VerifiedManifestBinding (certified_point,
network_magic, genesis_hash, immutable_range); load the Shelley genesis -> NativeGenesisConstants
(maxLovelaceSupply + activeSlotsCoeff, the latter parsed decimal-string -> exact rational with NO float
arithmetic) + the genesis epochLength; derive the certified slot's epoch from the CLOSED per-network
Shelley boundary (mainnet epoch 208 / slot 4_492_800; preprod epoch 4 / slot 86_400; preview epoch 0 /
slot 0 -- an unknown magic is terminal, never a guessed boundary) + the genesis epoch length -> the
manifest_epoch; decode_native_nonutxo_state(state, certified_point, manifest_epoch, network_magic) ->
(s1a, s1a_commitment) (S1a, the snapshot's own NES epoch cross-checked == manifest_epoch);
materialize_tables_to_utxo(tables, CONWAY_ERA_INDEX, None) -> UTxOState (S1c, the WHOLE file on the live
route); build the single-era Conway EraSchedule anchored at the snapshot epoch's ABSOLUTE first slot
(start_slot + (snapshot_epoch - start_epoch) * epoch_length) so locate(certified_slot).epoch ==
snapshot_epoch AND derive_epoch_window(schedule, snapshot_epoch) CONTAINS the certified slot;
bootstrap_from_native_mithril_snapshot(s1a, s1a_commitment, utxo, binding, genesis_constants,
manifest_bytes, chaindb, chaindb, wal, era_schedule, ledger_view) (S1b) -> the MithrilBootstrapOutput.
The persistent ChainDb / FileWalStore are REUSED (not re-opened); the leadership view is built faithfully
from the assembled consensus inputs (the cold-start composition never consumes it). (c) THE CLI-SEED IS
FORBIDDEN ON THE NATIVE ROUTE: a forbidden flag (--json-seed-path / --consensus-inputs-path) supplied
ALONGSIDE the native inputs is a structured TERMINAL NativeRouteForbiddenFlag error BEFORE any decode (no
ambiguous / half-authoritative bootstrap, no fallback, no silent ignore); the native route reaches NONE
of import_cardano_cli_json_utxo / import_live_consensus_inputs. (d) FAILURE SEMANTICS (TERMINAL before
authority visibility -- the WAL commit-point inside bootstrap_from_native_mithril_snapshot is the SOLE
discovery gate): a missing / mixed component (manifest / state / tables / shelley genesis not all present)
-> terminal before any decode; a malformed manifest / shelley genesis -> terminal; a manifest / point /
network / era mismatch -> terminal (the S1a epoch cross-check + the S1b point-coherence gate); a decode
(S1a) / materialize (S1c) / assemble (S1b) / persist failure -> terminal. Every failure leaves NO bootable
partial authority state and NO fallback to the cardano-cli / JSON seed. SCOPE: the live FirstRun
INVOCATION wiring ONLY -- S1a/S1b/S1c are FROZEN (reused unchanged), no new state machinery. NOT cold
restart / warm-start recovery / ChainSync / follow (S2, the release gate), NOT the Conway per-byte
min-UTxO calculator (DC-LEDGER-PARAMS-01 release blocker). The legacy CLI-seed FirstRun body remains a
SEPARATE explicitly-selected route (state/tables absent), NEVER a fallback from the native route.
- Source
docs/clusters/MITHRIL-VERIFIED-ANCHOR-INTEGRATION/SLICE-S1d-live-firstrun-native.md; user directive 2026-06-24 (S1d = wire the live --mode node FirstRun to the native Mithril bootstrap: route manifest + state + tables + Shelley genesis through the unchanged S1a/S1b/S1c chain, forbid the cardano-cli/JSON seed on the native route with a structured terminal on a forbidden flag, build the snapshot-epoch era schedule from the genesis + the per-network Shelley boundary without the operator bundle, and prove it hermetically + live against the real preprod snapshot; do NOT touch S1a/S1b/S1c, cold restart / warm-start / ChainSync, or the Conway per-byte min-UTxO calculator)
- Introduced in
- MITHRIL-VERIFIED-ANCHOR-INTEGRATION-S1d
Enforcement trace
Code
Tests 12
- native_first_run_forbidden_json_seed_is_terminal
- native_first_run_forbidden_consensus_inputs_is_terminal
- native_first_run_missing_manifest_is_terminal
- native_first_run_missing_shelley_genesis_is_terminal not on disk
- native_first_run_malformed_manifest_is_terminal
- native_first_run_malformed_shelley_genesis_is_terminal
- native_first_run_real_snapshot_invokes_bootstrap_and_persists
- native_first_run_real_snapshot_wrong_network_is_terminal
- preprod_snapshot_epoch_window_contains_manifest_point
- shelley_genesis_active_slots_coeff_decimal_to_rational
- parse_native_shelley_genesis_extracts_constants
- unknown_network_magic_has_no_boundary
Cross-references
Attack rationale
Two bootstrap-authority corruption classes are closed at the LIVE invocation boundary -- the gap S1b explicitly left open ('NOT WIRED LIVE: the --mode node FirstRun arm still seeds from --json-seed-path + --consensus-inputs-path'). (1) Operator-seed substitution on the live path: until S1d, the live FirstRun arm seeded the authority from the cardano-cli --json-seed + the operator --consensus-inputs bundle, so an operator could boot an attacker-chosen ledger / stake distribution divorced from the verified Mithril snapshot -- the provenance the manifest binding exists to guarantee, defeated at the one place it matters (the live node). Closed by routing the native FirstRun through the snapshot-only chain whose orchestration body references NONE of the CLI-seed importers (the ci gate's negative-controlled file-grep over the cfg(test)-stripped native_firstrun.rs + the first_run_native_mithril_bootstrap dispatch fails on any import_cardano_cli_json_utxo / import_live_consensus_inputs token), and by making a forbidden flag supplied ALONGSIDE the native inputs a structured terminal NativeRouteForbiddenFlag BEFORE any decode -- so there is no ambiguous half-authoritative path and no silent precedence. (2) Wrong-geometry epoch schedule: the native assembly cross-checks the decoded NES epoch against the epoch the era schedule resolves for the certified slot; a schedule built with the WRONG network boundary (e.g. the slot/epoch_length simplification that ignores the Byron offset, which computes epoch 292 for the preprod snapshot whose true NES epoch is 296) would make every real snapshot fail the coherence gate -- or, worse, a hand-tuned wrong schedule could admit an incoherent epoch. Closed by deriving the schedule from the CLOSED per-network Shelley boundary (the reviewed committed table: preprod epoch 4 / slot 86_400, mainnet epoch 208 / slot 4_492_800) + the genesis epoch length, anchored at the snapshot epoch's absolute first slot so locate(certified_slot).epoch == the decoded epoch and the derived window contains the certified slot (the load-bearing cross-check is a hermetic test asserting epoch 296 + window [126_230_400, 126_662_399] contains 126_400_064 for the real snapshot), with an unknown magic terminal (never a guessed boundary). Additionally the activeSlotsCoeff is parsed decimal-string -> exact rational with NO float in the authoritative state (BLUE no-float discipline preserved through the live ingress), and every component-missing / mismatch / decode / materialize / persist failure is terminal before the WAL commit-point -> no bootable partial state.
Evidence notes
Introduced as MITHRIL-VERIFIED-ANCHOR-INTEGRATION S1d (2026-06-24), the live-invocation wiring that resolves the DC-MITHRIL-03 open obligation ('NOT YET PROVEN: the live node can invoke that authority path from snapshot files. BLOCKED BY: the Stage-2 tables -> UTxOState promotion + the live FirstRun input contract') now that DC-MITHRIL-06 (S1c) shipped the tables -> UTxOState materialization. STEP-0 RESOLUTION (the key risk, both open questions resolved with NO fabricated input): (a) THE ERA SCHEDULE -- the native assembly needs the schedule only to locate(certified_slot).epoch and derive_epoch_window(schedule, snapshot_epoch); a single-era Conway schedule anchored at (start_epoch = snapshot_epoch, start_slot = the epoch's absolute first slot, epoch_length) satisfies both. The operator-forbidden geometry (make_node_schedule from canonical.epoch_start_slot) is replaced by genesis epochLength + the CLOSED per-network Shelley boundary (preprod epoch 4 / slot 86_400, VERIFIED against the live-run consensus-inputs.json epoch-292 epoch_start_slot 124_502_400 = 86_400 + (292-4)*432_000, and against the reviewed committed table in genesis_parser_corpus.rs). (b) THE GENESIS CONSTANTS -- the real preprod shelley-genesis.json carries maxLovelaceSupply (45e15), activeSlotsCoeff (0.05 -> exact rational {1,20}, no float), epochLength (432_000); the node lacked a --mode node real-Shelley-genesis flag, so --shelley-genesis-path was added (the contract's required metadata file). VERIFIED HERMETIC: cargo build --workspace clean; the 4 native_firstrun unit tests green (incl. preprod_snapshot_epoch_window_contains_manifest_point: the schedule yields epoch 296 + window [126_230_400, 126_662_399] containing the snapshot tip slot 126_400_064); the 6 dispatch-level tests green (forbidden --json-seed-path / --consensus-inputs-path terminal; missing manifest / shelley genesis terminal; malformed manifest / shelley genesis terminal -- via the real run_node_lifecycle_inner); ci/ci_check_native_firstrun_no_cli_seed.sh PASS (negative-controlled: it fails on an injected import_live_consensus_inputs in the native body AND on a removed --json-seed-path forbidden arm); ci/ci_check_registry_unique_ids.sh PASS (DC-MITHRIL-07 fresh). VERIFIED LIVE (the strongest proof): crates/ade_node/tests/native_firstrun_live.rs ran the native FirstRun over the REAL preprod snapshot (.mithril-scratch/restore-ancillary/db/ledger/126400064: state 28_446_335 bytes + tables 896_137_795 bytes) + the real .cardano-node-preprod/config/shelley-genesis.json + a CONSTRUCTED point-coherent manifest (slot 126_400_064, epoch 296, magic 1, genesis hash 162d29c4...; FLAGGED: no real Mithril manifest exists for THIS exact snapshot point -- the committed docs/evidence/mithril-manifest.json certifies a DIFFERENT point, slot 125928174 / epoch 295 -- so per the S1d contract a point-coherent manifest was constructed for the run, its block hash bound through since the S1a decoder does not re-derive the tip hash from the state file). The native bootstrap PERSISTED the durable artifacts: MithrilBootstrapOutput with a Mithril anchor whose seed_point.slot == 126_400_064, anchor_fp 7d98f1e99d46c0c2b3db510868bf6cdfd79398f871e935523cf341448705257c, the recovered-anchor point discoverable via load_recovered_anchor_point (== the snapshot slot), the seed-epoch sidecar present, exactly one WAL provenance commit; and a wrong-network (mainnet-magic) manifest over the same real bytes is terminal with NOTHING committed (no discoverable anchor lineage, no bootable partial state). NO cardano-cli / JSON seed reached. Gated on targeted suites (NOT cargo test -p ade_testkit -- the pre-existing all_epoch_boundaries_fire hang). SCOPE FENCE: the live FirstRun INVOCATION wiring ONLY; S1a/S1b/S1c FROZEN; NOT cold restart / warm-start recovery / ChainSync (S2), NOT the Conway per-byte min-UTxO calculator (DC-LEDGER-PARAMS-01).