ITADN

Add experimental `AnyNewEpochState` parameterised on `Era` to eliminate partial `sbeToEra` conversions

#1190Opencarbolymer 创建于 2026-04-27
C
carbolymercommented
## Problem `AnyNewEpochState` in `Cardano.Api.LedgerState` carries a `ShelleyBasedEra era` witness: ```haskell data AnyNewEpochState where AnyNewEpochState :: ShelleyBasedEra era -> ShelleyAPI.NewEpochState (ShelleyLedgerEra era) -> Ledger.LedgerTables ... -> AnyNewEpochState ``` Consumers in `cardano-testnet` that need `EraCommonConstraints` (via `obtainCommonConstraints`) must first convert `ShelleyBasedEra era` to `Exp.Era era` using `sbeToEra`. Because `Exp.Era` only inhabits Conway and Dijkstra, `sbeToEra` is partial for pre-Conway eras, forcing every call site to use a helper like: ```haskell unsafeEraFromSbe :: HasCallStack => ShelleyBasedEra era -> Era era unsafeEraFromSbe = withFrozenCallStack $ either (error . prettyShow . prettyError) id . sbeToEra ``` This appears in `EpochStateProcessing.hs` and is used across multiple modules (`Components/Query.hs`, `Runtime.hs`, `Process/Cli/SPO.hs`). Every pattern match on `AnyNewEpochState` in testnet code repeats the same partial conversion. See [cardano-node PR #6551](https://github.com/IntersectMBO/cardano-node/pull/6551) for context and the review discussion that motivated this issue. ## Constraint `foldEpochState` replays the chain from genesis via a pipelined chain-sync client. The callback receives blocks from all eras (Shelley through Dijkstra), so the existing `AnyNewEpochState` with `ShelleyBasedEra` must remain available for consumers that need full-era coverage (e.g. `cardano-cli debug log-epoch-state`). ## Proposal Add a new existential type in `Cardano.Api.Experimental` that carries an `Era era` witness instead of `ShelleyBasedEra era`: ```haskell -- | Like 'AnyNewEpochState' but restricted to experimental (Conway+) eras, -- so that 'obtainCommonConstraints' is always total. data AnyNewEpochState where AnyNewEpochState :: Era era -> ShelleyAPI.NewEpochState (ShelleyLedgerEra era) -> Ledger.LedgerTables ... -> AnyNewEpochState ``` Optionally, provide one or both of: 1. **A conversion function** from the legacy type to `Maybe` the experimental type (fails for pre-Conway eras). 2. **A wrapper around `foldEpochState`** that silently skips pre-Conway blocks and delivers only `Exp.AnyNewEpochState` to the callback, for consumers that only care about Conway+ governance state. ## Migration path - **cardano-testnet**: switch to the experimental `AnyNewEpochState`. All `unsafeEraFromSbe` calls and the helper itself can be removed; `obtainCommonConstraints` works directly on the `Era` witness. - **cardano-cli** (`debug log-epoch-state`): continues using the legacy `AnyNewEpochState` with `ShelleyBasedEra`, unaffected by this change. ## Alternatives considered - **Make `sbeToEra` total**: not possible without adding pre-Conway constructors to `Era`, which defeats the purpose of the experimental API. - **Keep the status quo**: every new testnet module repeats the same partial conversion boilerplate, and `error` calls in test infrastructure are fragile.
0 条评论