-
Notifications
You must be signed in to change notification settings - Fork 7
ADR-016 Backwards and Forwards Compatibility #79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,136 @@ | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # ADR-016: Backwards and Forwards Compatibility | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| **Status:** Proposed | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| **Date:** 2025-10-07 | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Context | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| We are working on [a new API](./ADR-004-Support-only-for-mainnet-and-upcoming-eras.md) for `cardano-api` that is centred around the `Era era` type. We would like to maintain backwards compatibility with the "old" api under two conditions: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| 1) Existing exposed functionality that uses the "old" api which may be in use. | ||||||||||||||||||||||||||
| 2) Any functionality needed to enable QA's ability to test hardforking from Byron to the current era. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Proposed Solution | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| The solution proposed below is specific to certificates but can be expanded to any era depdendent type. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Our "old" Certificate definition is as follows: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ```haskell | ||||||||||||||||||||||||||
| data Certificate era where | ||||||||||||||||||||||||||
| -- Pre-Conway | ||||||||||||||||||||||||||
| ShelleyRelatedCertificate | ||||||||||||||||||||||||||
| :: Typeable era | ||||||||||||||||||||||||||
| => ShelleyToBabbageEra era | ||||||||||||||||||||||||||
| -> Ledger.ShelleyTxCert (ShelleyLedgerEra era) | ||||||||||||||||||||||||||
| -> Certificate era | ||||||||||||||||||||||||||
| -- Conway onwards | ||||||||||||||||||||||||||
| ConwayCertificate | ||||||||||||||||||||||||||
| :: Typeable era | ||||||||||||||||||||||||||
| => ConwayEraOnwards era | ||||||||||||||||||||||||||
| -> Ledger.ConwayTxCert (ShelleyLedgerEra era) | ||||||||||||||||||||||||||
| -> Certificate era | ||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| `Cardano.Api.Certificate` exposes several helper functions that use this "old" type. E.g `makeStakeAddressDelegationCertificate`, `makeStakeAddressRegistrationCertificate` and `makeStakeAddressUnregistrationCertificate` to name a few. All of these "old" functions will be deprecated in favour of a new API that allows us to expose functionality from any era required without adding significant boilerplate as seen in the above definition of `data Certificate era`. We achieve this by the following: | ||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not link to IntersectMBO/cardano-api#962 as an example. The inline example is much better, but still, being able to easily check the other one could help too. |
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Replace era-variant GADTs (like Certificate era) with a uniform wrapper (Certificate :: L.TxCert era -> Certificate era) and using open type families to resolve era-specific types (e.g., Delegatee era). Era constraints (IsEra, IsShelleyBasedEra) gate access to functionality. | ||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The example below uses a closed type family |
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| I will make this clearer with an example below. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| **NB**: We will only implement functionality constrained by `IsShelleyBasedEra era` and `IsEra era` that either is currently exposed by the "old" api or specifically required by QA. If we do not need backwards compatibility then we will use`Era era` or `IsEra era` without implementing an additional type synonym family. | ||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There is no space between "use" and "
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: use |
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Let's use `makeStakeAddressDelegationCertificate` as an example. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ```haskell | ||||||||||||||||||||||||||
| data StakeDelegationRequirements era where | ||||||||||||||||||||||||||
| StakeDelegationRequirementsConwayOnwards | ||||||||||||||||||||||||||
| :: ConwayEraOnwards era | ||||||||||||||||||||||||||
| -> StakeCredential | ||||||||||||||||||||||||||
| -> Ledger.Delegatee | ||||||||||||||||||||||||||
| -> StakeDelegationRequirements era | ||||||||||||||||||||||||||
| StakeDelegationRequirementsPreConway | ||||||||||||||||||||||||||
| :: ShelleyToBabbageEra era | ||||||||||||||||||||||||||
| -> StakeCredential | ||||||||||||||||||||||||||
| -> PoolId | ||||||||||||||||||||||||||
| -> StakeDelegationRequirements era | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| makeStakeAddressDelegationCertificate :: StakeDelegationRequirements era -> Certificate era | ||||||||||||||||||||||||||
| makeStakeAddressDelegationCertificate = \case | ||||||||||||||||||||||||||
| StakeDelegationRequirementsConwayOnwards cOnwards scred delegatee -> | ||||||||||||||||||||||||||
| conwayEraOnwardsConstraints cOnwards $ | ||||||||||||||||||||||||||
| ConwayCertificate cOnwards $ | ||||||||||||||||||||||||||
| Ledger.mkDelegTxCert (toShelleyStakeCredential scred) delegatee | ||||||||||||||||||||||||||
| StakeDelegationRequirementsPreConway atMostBabbage scred pid -> | ||||||||||||||||||||||||||
| shelleyToBabbageEraConstraints atMostBabbage $ | ||||||||||||||||||||||||||
| ShelleyRelatedCertificate atMostBabbage $ | ||||||||||||||||||||||||||
| Ledger.mkDelegStakeTxCert (toShelleyStakeCredential scred) (unStakePoolKeyHash pid) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| -- The `StakeDelegationRequirements era` GADT will necessitate more data constructors if there are any changes to the requirements of stake delegation in future eras. | ||||||||||||||||||||||||||
| -- This is already seen in the transition from Babbage (can only delegate to stake pools) -> Conway (can delegate to stake pools and dreps). | ||||||||||||||||||||||||||
| -- This obviously does not scale in the face of possible incoming changes and requires the propagation of an additional data constructor. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| -- I propose the following: | ||||||||||||||||||||||||||
|
Comment on lines
+73
to
+77
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These comments could be unquoted. I think that would make it easier to parse |
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| -- Already exists in Cardano.Api.Experimental.Tx.Internal.Certificate | ||||||||||||||||||||||||||
| data Certificate era where | ||||||||||||||||||||||||||
| Certificate :: L.EraTxCert era => L.TxCert era -> Certificate era | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| -- Type family definition capturing the change of possible delegatees. We can now delegate to stake pools or dreps or delegate | ||||||||||||||||||||||||||
| -- to dreps and stake pools simultaneously. This is captured in the `Ledger.Delegatee` type. | ||||||||||||||||||||||||||
| type family Delegatee era where | ||||||||||||||||||||||||||
| Delegatee ConwayEra = Ledger.Delegatee | ||||||||||||||||||||||||||
| Delegatee BabbageEra = Api.Hash Api.StakePoolKey | ||||||||||||||||||||||||||
| Delegatee AlonzoEra = Api.Hash Api.StakePoolKey | ||||||||||||||||||||||||||
| ... | ||||||||||||||||||||||||||
| ... | ||||||||||||||||||||||||||
| Delegate ShelleyEra = Api.Hash Api.StakePoolKey | ||||||||||||||||||||||||||
|
Comment on lines
+86
to
+91
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| makeStakeAddressDelegationCertificate | ||||||||||||||||||||||||||
| :: forall era | ||||||||||||||||||||||||||
| . IsEra era | ||||||||||||||||||||||||||
| => StakeCredential | ||||||||||||||||||||||||||
| -> Delegatee era | ||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||
| -> Certificate (LedgerEra era) | ||||||||||||||||||||||||||
| makeStakeAddressDelegationCertificate sCred delegatee = | ||||||||||||||||||||||||||
| case useEra @era of | ||||||||||||||||||||||||||
| e@ConwayEra -> | ||||||||||||||||||||||||||
| obtainCommonConstraints e $ | ||||||||||||||||||||||||||
| Certificate $ | ||||||||||||||||||||||||||
| Ledger.mkDelegTxCert (Api.toShelleyStakeCredential sCred) delegatee | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| --- BELOW IS IN A SEPARATE "COMPATIBLE" MODULE DESIGNED FOR BACKWARDS COMPATIBILITY. | ||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This already implies that the function above is not backwards compatible, but I would say it explicitly, so that the difference is more obvious to the reader. I would even explicitly say that |
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| makeStakeAddressDelegationCertificate | ||||||||||||||||||||||||||
| :: forall era | ||||||||||||||||||||||||||
| . IsShelleyBasedEra era | ||||||||||||||||||||||||||
| => StakeCredential | ||||||||||||||||||||||||||
| -> Delegatee era | ||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||
| -> Certificate (LedgerEra era) | ||||||||||||||||||||||||||
| makeStakeAddressDelegationCertificate sCred delegatee = | ||||||||||||||||||||||||||
| case shelleyBasedEra @era of | ||||||||||||||||||||||||||
| ... | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| -- All functions using the old Certificate era GADT will be marked {-# DEPRECATED #-} | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| We remove entirely the need to define a type like `StakeDelegationRequirements era`. The type synonym family is now responsible for resolving the era dependent type. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Decision | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| The ADR gets adopted in `cardano-api`. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Consequences | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - An additional type synonym family per era dependent type. | ||||||||||||||||||||||||||
| - Removal of all the "old" api's data definitions that capture the notion of backwards compatibility. | ||||||||||||||||||||||||||
| - Removal of all helper functions that use these data definitions described in the aforementioned point. | ||||||||||||||||||||||||||
| - Implementation of new equivalent helper functions that utilize a type synonym family for the era dependent type. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.