Invariants / DC-LEDGER-PARAMS-01

DC-LEDGER-PARAMS-01

DC true enforced

Imported protocol parameters are preserved era-faithfully and are NEVER semantically remapped across eras. The shared ProtocolParameters carries the minimum-UTxO rule as an era-aware sum type MinUtxoRule = LegacyAbsoluteMin(Coin) | PerByte(Coin) (NOT a single Coin field): Shelley/Mary minUTxOValue is an ABSOLUTE per-output floor (output.coin >= c); Conway coinsPerUTxOByte is a PER-BYTE coefficient (the minimum is c * serialized-output-size, NOT an absolute floor). The native non-UTxO snapshot decoder (read_conway_pparams) decodes Conway coinsPerUTxOByte into MinUtxoRule::PerByte(Coin(c)) and MUST NOT populate LegacyAbsoluteMin from it. The authoritative min-UTxO VALIDATION matches on the rule: LegacyAbsoluteMin(c) runs the existing absolute check; PerByte(_) is a structured TERMINAL LedgerError::UnsupportedConwayMinUtxoRule (fail closed rather than accept outputs under a false minimum -- the per-byte coefficient is NEVER used as an absolute floor). The canonical pparams encoders (encode_pparams, fingerprint_pparams) serialize the rule's coin payload only, BYTE-IDENTICAL to the prior single-Coin field for legacy LegacyAbsoluteMin states (so the pinned non-Conway pparams fingerprints + all differential replay suites are unchanged); the rule KIND is bound separately in the S1a native commitment (bumped to v2). DERIVED bind: the native decoder's internal network_id is DERIVED from the manifest network magic (mainnet 764824073 -> 1; any other (testnet) magic -> 0) and bound onto the emitted state, protocol_params.network_id, and the commitment, so ONE manifest binds every authority-bearing field. The pool reward-account network nibble is OPERATOR-controlled ledger data (demonstrably MIXED on real preprod) and is NOT a network discriminator: it is recorded as a DIAGNOSTIC RewardNibbleObservation (Uniform/Mixed/None) in the canonical report and NEVER accepts or rejects the snapshot -- a heuristic on operator metadata, unanimous or otherwise, is not an authority check; the manifest magic is the SOLE network authority. RELEASE BLOCKER -- a DERIVED compatibility PREREQUISITE for native Conway block validation/follow, NOT merely a full-compatibility enhancement: Ade's Conway min-UTxO validation must compute the era-correct per-byte minimum before a native-bootstrapped Conway state (which carries PerByte) can be validated/followed; until then the per-byte path refuses deterministically (UnsupportedConwayMinUtxoRule). SCOPE: the min-UTxO rule preservation + the per-byte validation terminal + the network-id derive/bind + the diagnostic nibble observation; the era-correct per-byte minimum COMPUTATION is future work (the terminal is the fail-closed placeholder for it).

Source

docs/clusters/MITHRIL-VERIFIED-ANCHOR-INTEGRATION/SLICE-S1a-native-nonutxo-decoder.md; user directive 2026-06-23 (two S1a refinements, neither deferrable behind a flag: (1) bind network_id from the manifest network magic -- mainnet -> 1, testnet -> 0 -- onto every authority-bearing field (the operator-supplied reward-account nibble is diagnostic evidence only, never a verdict -- the manifest magic is the sole network authority); (2) preserve Conway coinsPerUTxOByte faithfully as MinUtxoRule::PerByte, NEVER remapped into an absolute min_utxo_value, with the per-byte min-UTxO validation a structured TERMINAL UnsupportedConwayMinUtxoRule rather than a permissive absolute floor)

Introduced in
MITHRIL-VERIFIED-ANCHOR-INTEGRATION-S1a

Enforcement trace

Tests 7

  • network_id_derived_from_manifest_magic
  • reward_nibble_disagreement_is_diagnostic_not_terminal
  • conway_pparams_decode_yields_per_byte_min_utxo_rule
  • mary_min_utxo_per_byte_rule_is_terminal_not_permissive
  • mary_min_utxo_legacy_absolute_min_unchanged
  • commitment_binds_every_field
  • decode_native_nonutxo_real_snapshot

Cross-references

Attack rationale

Two cross-era / cross-network correctness losses are closed. (1) Semantic remap of a per-byte rule into an absolute floor: if Conway coinsPerUTxOByte (4310 on real preprod) were stored on the old absolute min_utxo_value field, the legacy min-UTxO check output.coin >= min_utxo_value would treat 4310 as an absolute lovelace floor and ADMIT outputs that are actually under the era-correct per-byte minimum (4310 * serialized-size, e.g. an output needs ~1M lovelace) -- a false minimum that accepts dust the real network rejects, undermining ledger-validation compatibility. Closed by the era-aware MinUtxoRule sum type (PerByte is a distinct variant, never collapsed onto the absolute floor) + a structured TERMINAL UnsupportedConwayMinUtxoRule on the per-byte path (fail closed rather than accept under a false minimum; the per-byte minimum computation is future work, and until then the path refuses deterministically rather than guessing). The legacy absolute path is unchanged (regression-tested), and BYTE-IDENTITY of the coin payload keeps the entire differential replay corpus behaviour-invariant. (2) Wrong-network binding: an imported state must be bound to the intended network or a forge/validation could run against the wrong network's identity. Closed by deriving network_id from the manifest magic (the SOLE authority) and binding it onto every authority-bearing field + the commitment. The V2 state file carries NO network-authoritative identity field of its own; the only network-bound datum (pool reward-account stake-address header nibbles) is OPERATOR-supplied and demonstrably MIXED on real preprod (both net-0 and net-1 pool reward accounts coexist), so it is recorded as a DIAGNOSTIC RewardNibbleObservation (Uniform/Mixed/None) in the canonical report and NEVER accepts or rejects the snapshot -- a unanimous-only terminal would be a heuristic masquerading as an authority check; a stronger decoded cross-check awaits a genuinely network-authoritative snapshot field.

Evidence notes

Two S1a refinements (2026-06-23), neither deferred behind a flag. CHANGE 2 (min_utxo_rule): replaced ProtocolParameters.min_utxo_value: Coin with min_utxo_rule: MinUtxoRule across every compiler-guided consumer -- the Shelley/Mary min-UTxO checks (shelley.rs/mary.rs match MinUtxoRule: LegacyAbsoluteMin keeps the absolute behavior, PerByte -> UnsupportedConwayMinUtxoRule), the governance update apply (pparams.rs:551, applies as LegacyAbsoluteMin -- the ProtocolParameterUpdate proposal field stays Option), Default (LegacyAbsoluteMin(1_000_000)), the snapshot pparams codec (gov_state.rs encode/decode serialize/reconstruct via coin()), the fingerprint (fingerprint.rs writes coin()), and the literal constructors in byron.rs/mary.rs/shelley.rs/consensus_inputs/protocol_params.rs/snapshot_loader.rs/translation_summary_proof.rs. CHANGE 1 (network_id): added network_id_from_magic + the 4th decode arg manifest_network_magic + network_id on the state/pparams/commitment + NetworkIdentityMismatch. EMPIRICAL: the real preprod snapshot (epoch 296) reward accounts are MIXED net-0/net-1 (operator-supplied), so the reward nibble is recorded as a DIAGNOSTIC RewardNibbleObservation (never a verdict, terminal or otherwise); the real snapshot decodes cleanly reporting network_id=0 + min_utxo_rule=PerByte(4310). Verified: cargo test -p ade_ledger lib (663) green; ledgerdb_nonutxo_hermetic (16, incl. 4 new) green; the real-snapshot decode_native_nonutxo_real_snapshot green (network_id=0, PerByte(4310)); the replay-relevant differential suites (shelley/allegra_mary/alonzo_babbage_conway) + ledger_determinism (8) + boundary_fingerprint_agreement (1) green -- BYTE-IDENTITY of the legacy coin payload preserved; ci_check_native_nonutxo_decode.sh + ci_check_ledgerdb_state_decode.sh PASS. Gated on targeted suites (NOT cargo test -p ade_testkit -- a pre-existing all_epoch_boundaries_fire hang in epoch_boundary_logic.rs). NOT YET: the era-correct Conway per-byte minimum computation (the RELEASE BLOCKER the UnsupportedConwayMinUtxoRule terminal stands in for); a network-authoritative snapshot field (the reward nibble stays diagnostic-only until one exists). NOT persisted (S1b scope fence).