Skip to content

Commit

Permalink
Use era names for constructors in new Era API
Browse files Browse the repository at this point in the history
  • Loading branch information
carbolymer committed Jul 24, 2024
1 parent fc03c3e commit ea49f47
Showing 1 changed file with 36 additions and 100 deletions.
136 changes: 36 additions & 100 deletions cardano-api/internal/Cardano/Api/Protocol/AvailableEras.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,8 @@ import GHC.TypeLits
-- | Users typically interact with the latest features on the mainnet or experiment with features
-- from the upcoming era. Hence, the protocol versions are limited to the current mainnet era
-- and the next era (upcoming era).


{-# DEPRECATED BabbageEra "We are currently in the Conway era. Please update your type Signature to ConwayEra" #-}

data BabbageEra

data ConwayEra
Expand All @@ -56,115 +55,52 @@ type family ToConstrainedEra era = (r :: Type) | r -> era where
ToConstrainedEra BabbageEra = Ledger.Babbage
ToConstrainedEra ConwayEra = Ledger.Conway

{- | Represents the eras in Cardano's blockchain.
Instead of enumerating every possible era, we use two constructors:
'CurrentEra' and 'UpcomingEra'. This design simplifies the handling
of eras, especially for 'cardano-api' consumers who are primarily concerned
with the current mainnet era and the next era for an upcoming hardfork.
Usage:
- 'CurrentEra': Reflects the era currently active on mainnet.
- 'UpcomingEra': Represents the era planned for the next hardfork.
After a hardfork, 'cardano-api' should be updated promptly to reflect
the new mainnet era in 'CurrentEra'.
-}

-- | Represents the eras in Cardano's blockchain.
-- This type represents eras currently on mainnet and new eras which are
-- in development.
--
-- After a hardfork, the from which we hardfork from gets deprecated and
-- after deprecation period, gets removed. During deprecation period,
-- consumers of cardano-api should update their codebase to the mainnet era.
data Era era where
-- | Deprecated era, Do not use.
BabbageEra :: Era BabbageEra
-- | The era currently active on Cardano's mainnet.
CurrentEra :: Era ConwayEra
-- | The era planned for the next hardfork on Cardano's mainnet.
UpcomingEra :: UninhabitableType EraCurrentlyNonExistent => Era (UninhabitableType EraCurrentlyNonExistent)




{- | How to deprecate an era
1. Add DEPRECATED pragma to the era type tag.
@
{-# DEPRECATED BabbageEra "BabbageEra no longer supported, use ConwayEra" #-}
data BabbageEra
@
2. Add a new era type tag.
@
data Era era where
-- | The era currently active on Cardano's mainnet.
CurrentEra :: Era ConwayEra
-- | The era planned for the next hardfork on Cardano's mainnet.
UpcomingEra :: Era (UninhabitableType EraCurrentlyNonExistent)
@
3. Add new 'UseEra' instance and keep the deprecated era's instance.
@
instance UseEra BabbageEra where
useEra = error "useEra: BabbageEra no longer supported, use ConwayEra"
instance UseEra ConwayEra where
useEra = CurrentEra
@
4. Update 'protocolVersionToSbe' as follows:
@
protocolVersionToSbe
:: Era era
-> Maybe (ShelleyBasedEra (AvailableErasToSbe era))
protocolVersionToSbe CurrentEra = Just ShelleyBasedEraBabbage
protocolVersionToSbe UpcomingEra = Nothing
@
-}


{- | 'CurrentEra' and 'UpcomingEra' are for internal use only.
The above restriction combined with the following pattern synonyms
prevents a user from pattern matching on 'Era era' and
avoids the following situation:
@
doThing :: Era era -> ()
doThing = \case
CurrentEra -> enableFeature
UpcomingEra -> disableFeature
@
Consumers of this library must pick one of the two eras while
this library is responsibile for what happens at the boundary of the eras.
-}


ConwayEra :: Era ConwayEra

-- | How to deprecate an era
--
-- 1. Add DEPRECATED pragma to the era type tag and the era constructor at the same time:
-- @
-- {-# DEPRECATED BabbageEra "BabbageEra no longer supported, use ConwayEra" #-}
-- data BabbageEra
-- @
--
-- 2. Update haddock for the constructor of the deprecated era, mentioning deprecation.
--
--
-- 3. Add new 'UseEra' instance and update the deprecated era instance to produce a compile-time error:
-- @
-- instance TypeError ('Text "UseEra BabbageEra: Deprecated. Update to ConwayEra") => UseEra BabbageEra where
-- useEra = error "unreachable"
--
-- instance UseEra ConwayEra where
-- useEra = ConwayEra
-- @
protocolVersionToSbe
:: Era era
-> Maybe (ShelleyBasedEra (AvailableErasToSbe era))
protocolVersionToSbe CurrentEra = Just ShelleyBasedEraConway
protocolVersionToSbe BabbageEra = Just ShelleyBasedEraBabbage
protocolVersionToSbe ConwayEra = Just ShelleyBasedEraConway

-------------------------------------------------------------------------

-- | Type class interface for the 'Era' type.

class UseEra era where
useEra :: Era era

instance UseEra BabbageEra where
useEra = error "UseEra BabbageEra: Deprecated. Update to ConwayEra"
instance TypeError ('Text "UseEra BabbageEra: Deprecated. Update to ConwayEra") => UseEra BabbageEra where
useEra = error "unreachable"

instance UseEra ConwayEra where
useEra = CurrentEra

-- | After a hardfork there is usually no planned upcoming era
-- that we are able to experiment with. We force a type era
-- in this instance. See docs above.
data EraCurrentlyNonExistent

type family UninhabitableType a where
UninhabitableType EraCurrentlyNonExistent =
TypeError ('Text "There is currently no planned upcoming era. Use CurrentEra instead.")



doStuff :: Era era -> IO ()
doStuff CurrentEra = {- feature supported -} pure ()
doStuff UpcomingEra = error "feature not supported"
useEra = ConwayEra

0 comments on commit ea49f47

Please sign in to comment.