Skip to content

Commit 3d885dc

Browse files
authored
Merge pull request #534 from IntersectMBO/deprecate-serialiseTxLedgerCddl
Deprecate `serialiseTxLedgerCddl`
2 parents f1531bc + 0266459 commit 3d885dc

File tree

4 files changed

+116
-128
lines changed

4 files changed

+116
-128
lines changed

cardano-api/internal/Cardano/Api/SerialiseLedgerCddl.hs

+91-124
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@
1111
-- | Ledger CDDL Serialisation
1212
--
1313
module Cardano.Api.SerialiseLedgerCddl
14-
( TextEnvelopeCddl(..)
15-
, TextEnvelopeCddlError (..)
14+
( TextEnvelopeCddlError (..)
1615
, FromSomeTypeCDDL(..)
1716

1817
-- * Reading one of several transaction or
@@ -41,7 +40,10 @@ import Cardano.Api.Error
4140
import Cardano.Api.HasTypeProxy
4241
import Cardano.Api.IO
4342
import Cardano.Api.Pretty
44-
import Cardano.Api.SerialiseCBOR
43+
import Cardano.Api.SerialiseTextEnvelope (TextEnvelope (..),
44+
TextEnvelopeDescr (TextEnvelopeDescr), TextEnvelopeError (..),
45+
TextEnvelopeType (TextEnvelopeType), deserialiseFromTextEnvelope,
46+
legacyComparison, serialiseToTextEnvelope)
4547
import Cardano.Api.Tx.Sign
4648
import Cardano.Api.Utils
4749

@@ -51,17 +53,16 @@ import qualified Cardano.Ledger.Binary as CBOR
5153

5254
import Control.Monad.Trans.Except.Extra (firstExceptT, handleIOExceptT, hoistEither,
5355
newExceptT, runExceptT)
54-
import Data.Aeson
5556
import qualified Data.Aeson as Aeson
5657
import Data.Aeson.Encode.Pretty (Config (..), defConfig, encodePretty', keyOrder)
5758
import Data.Bifunctor (first)
5859
import Data.ByteString (ByteString)
59-
import qualified Data.ByteString.Base16 as Base16
6060
import qualified Data.ByteString.Lazy as LBS
6161
import Data.Data (Data)
62+
import Data.Either.Combinators (mapLeft)
6263
import qualified Data.List as List
6364
import Data.Text (Text)
64-
import qualified Data.Text.Encoding as Text
65+
import qualified Data.Text as T
6566

6667
-- Why have we gone this route? The serialization format of `TxBody era`
6768
-- differs from the CDDL. We serialize to an intermediate type in order to simplify
@@ -77,29 +78,6 @@ import qualified Data.Text.Encoding as Text
7778
-- ease removal of the non-CDDL spec serialization, we have opted to create a separate
7879
-- data type to encompass this in the interim.
7980

80-
data TextEnvelopeCddl = TextEnvelopeCddl
81-
{ teCddlType :: !Text
82-
, teCddlDescription :: !Text
83-
, teCddlRawCBOR :: !ByteString
84-
} deriving (Eq, Show)
85-
86-
instance ToJSON TextEnvelopeCddl where
87-
toJSON TextEnvelopeCddl {teCddlType, teCddlDescription, teCddlRawCBOR} =
88-
object [ "type" .= teCddlType
89-
, "description" .= teCddlDescription
90-
, "cborHex" .= Text.decodeUtf8 (Base16.encode teCddlRawCBOR)
91-
]
92-
93-
instance FromJSON TextEnvelopeCddl where
94-
parseJSON = withObject "TextEnvelopeCddl" $ \v ->
95-
TextEnvelopeCddl <$> (v .: "type")
96-
<*> (v .: "description")
97-
<*> (parseJSONBase16 =<< v .: "cborHex")
98-
where
99-
parseJSONBase16 v =
100-
either fail return . Base16.decode . Text.encodeUtf8 =<< parseJSON v
101-
102-
10381
data TextEnvelopeCddlError
10482
= TextEnvelopeCddlErrCBORDecodingError DecoderError
10583
| TextEnvelopeCddlAesonDecodeError FilePath String
@@ -111,6 +89,13 @@ data TextEnvelopeCddlError
11189
| TextEnvelopeCddlErrByronKeyWitnessUnsupported
11290
deriving (Show, Eq, Data)
11391

92+
textEnvelopeErrorToTextEnvelopeCddlError :: TextEnvelopeError -> TextEnvelopeCddlError
93+
textEnvelopeErrorToTextEnvelopeCddlError = \case
94+
TextEnvelopeTypeError expectedTypes actualType -> TextEnvelopeCddlTypeError (map (T.pack . show) expectedTypes)
95+
(T.pack $ show actualType)
96+
TextEnvelopeDecodeError decoderError -> TextEnvelopeCddlErrCBORDecodingError decoderError
97+
TextEnvelopeAesonDecodeError errorString -> TextEnvelopeCddlAesonDecodeError "" errorString
98+
11499
instance Error TextEnvelopeCddlError where
115100
prettyError = \case
116101
TextEnvelopeCddlErrCBORDecodingError decoderError ->
@@ -134,36 +119,35 @@ instance Error TextEnvelopeCddlError where
134119
TextEnvelopeCddlErrByronKeyWitnessUnsupported ->
135120
"TextEnvelopeCddl error: Byron key witnesses are currently unsupported."
136121

137-
serialiseTxLedgerCddl :: ShelleyBasedEra era -> Tx era -> TextEnvelopeCddl
138-
serialiseTxLedgerCddl era tx =
139-
shelleyBasedEraConstraints era $
140-
TextEnvelopeCddl
141-
{ teCddlType = genType tx
142-
, teCddlDescription = "Ledger Cddl Format"
143-
, teCddlRawCBOR = serialiseToCBOR tx
144-
-- The SerialiseAsCBOR (Tx era) instance serializes to the Cddl format
145-
}
146-
where
147-
genType :: Tx era -> Text
148-
genType tx' = case getTxWitnesses tx' of
149-
[] -> "Unwitnessed " <> genTxType
150-
_ -> "Witnessed " <> genTxType
151-
genTxType :: Text
152-
genTxType =
153-
case era of
154-
ShelleyBasedEraShelley -> "Tx ShelleyEra"
155-
ShelleyBasedEraAllegra -> "Tx AllegraEra"
156-
ShelleyBasedEraMary -> "Tx MaryEra"
157-
ShelleyBasedEraAlonzo -> "Tx AlonzoEra"
158-
ShelleyBasedEraBabbage -> "Tx BabbageEra"
159-
ShelleyBasedEraConway -> "Tx ConwayEra"
160-
161-
deserialiseTxLedgerCddl :: ()
162-
=> ShelleyBasedEra era
163-
-> TextEnvelopeCddl
164-
-> Either TextEnvelopeCddlError (Tx era)
165-
deserialiseTxLedgerCddl era tec =
166-
first TextEnvelopeCddlErrCBORDecodingError . deserialiseTx era $ teCddlRawCBOR tec
122+
{-# DEPRECATED serialiseTxLedgerCddl "Use 'serialiseToTextEnvelope' from 'Cardano.Api.SerialiseTextEnvelope' instead." #-}
123+
serialiseTxLedgerCddl :: ShelleyBasedEra era -> Tx era -> TextEnvelope
124+
serialiseTxLedgerCddl era tx = shelleyBasedEraConstraints era $
125+
(serialiseToTextEnvelope (Just (TextEnvelopeDescr "Ledger Cddl Format")) tx){teType = TextEnvelopeType $ T.unpack $ genType tx}
126+
where
127+
genType :: Tx era -> Text
128+
genType tx' = case getTxWitnesses tx' of
129+
[] -> "Unwitnessed " <> genTxType
130+
_ -> "Witnessed " <> genTxType
131+
genTxType :: Text
132+
genTxType =
133+
case era of
134+
ShelleyBasedEraShelley -> "Tx ShelleyEra"
135+
ShelleyBasedEraAllegra -> "Tx AllegraEra"
136+
ShelleyBasedEraMary -> "Tx MaryEra"
137+
ShelleyBasedEraAlonzo -> "Tx AlonzoEra"
138+
ShelleyBasedEraBabbage -> "Tx BabbageEra"
139+
ShelleyBasedEraConway -> "Tx ConwayEra"
140+
141+
{-# DEPRECATED deserialiseTxLedgerCddl "Use 'deserialiseFromTextEnvelope' from 'Cardano.Api.SerialiseTextEnvelope' instead." #-}
142+
deserialiseTxLedgerCddl :: forall era .
143+
ShelleyBasedEra era
144+
-> TextEnvelope
145+
-> Either TextEnvelopeError (Tx era)
146+
deserialiseTxLedgerCddl era =
147+
shelleyBasedEraConstraints era $ deserialiseFromTextEnvelope asType
148+
where
149+
asType :: AsType (Tx era)
150+
asType = shelleyBasedEraConstraints era $ proxyToAsType Proxy
167151

168152
writeByronTxFileTextEnvelopeCddl
169153
:: File content Out
@@ -175,75 +159,58 @@ writeByronTxFileTextEnvelopeCddl path w =
175159
where
176160
txJson = encodePretty' textEnvelopeCddlJSONConfig (serializeByronTx w) <> "\n"
177161

178-
serializeByronTx :: Byron.ATxAux ByteString -> TextEnvelopeCddl
162+
serializeByronTx :: Byron.ATxAux ByteString -> TextEnvelope
179163
serializeByronTx tx =
180-
TextEnvelopeCddl
181-
{ teCddlType = "Tx ByronEra"
182-
, teCddlDescription = "Ledger Cddl Format"
183-
, teCddlRawCBOR = CBOR.recoverBytes tx
164+
TextEnvelope
165+
{ teType = "Tx ByronEra"
166+
, teDescription = "Ledger Cddl Format"
167+
, teRawCBOR = CBOR.recoverBytes tx
184168
}
185169

186-
deserialiseByronTxCddl :: TextEnvelopeCddl -> Either TextEnvelopeCddlError (Byron.ATxAux ByteString)
170+
deserialiseByronTxCddl :: TextEnvelope -> Either TextEnvelopeCddlError (Byron.ATxAux ByteString)
187171
deserialiseByronTxCddl tec =
188172
first TextEnvelopeCddlErrCBORDecodingError $
189173
CBOR.decodeFullAnnotatedBytes
190174
CBOR.byronProtVer "Byron Tx"
191-
CBOR.decCBOR (LBS.fromStrict $ teCddlRawCBOR tec)
175+
CBOR.decCBOR (LBS.fromStrict $ teRawCBOR tec)
192176

193-
deserialiseTx :: ()
194-
=> ShelleyBasedEra era
195-
-> ByteString
196-
-> Either DecoderError (Tx era)
197-
deserialiseTx sbe =
198-
shelleyBasedEraConstraints sbe
199-
$ deserialiseFromCBOR (AsTx (proxyToAsType Proxy))
200-
201-
serialiseWitnessLedgerCddl :: forall era. ShelleyBasedEra era -> KeyWitness era -> TextEnvelopeCddl
202-
serialiseWitnessLedgerCddl sbe kw =
203-
TextEnvelopeCddl
204-
{ teCddlType = witEra sbe
205-
, teCddlDescription = genDesc kw
206-
, teCddlRawCBOR = cddlSerialiseWitness kw
207-
}
177+
serialiseWitnessLedgerCddl :: forall era. ShelleyBasedEra era -> KeyWitness era -> TextEnvelope
178+
serialiseWitnessLedgerCddl sbe kw = shelleyBasedEraConstraints sbe $
179+
serialiseToTextEnvelope (Just (TextEnvelopeDescr $ T.unpack $ genDesc kw)) kw
208180
where
209-
cddlSerialiseWitness :: KeyWitness era -> ByteString
210-
cddlSerialiseWitness (ShelleyBootstrapWitness era wit) = CBOR.serialize' (eraProtVerLow era) wit
211-
cddlSerialiseWitness (ShelleyKeyWitness era wit) = CBOR.serialize' (eraProtVerLow era) wit
212-
cddlSerialiseWitness ByronKeyWitness{} = case sbe of {}
213-
214181
genDesc :: KeyWitness era -> Text
215182
genDesc ByronKeyWitness{} = case sbe of {}
216183
genDesc ShelleyBootstrapWitness{} = "Key BootstrapWitness ShelleyEra"
217184
genDesc ShelleyKeyWitness{} = "Key Witness ShelleyEra"
218185

219-
witEra :: ShelleyBasedEra era -> Text
220-
witEra ShelleyBasedEraShelley = "TxWitness ShelleyEra"
221-
witEra ShelleyBasedEraAllegra = "TxWitness AllegraEra"
222-
witEra ShelleyBasedEraMary = "TxWitness MaryEra"
223-
witEra ShelleyBasedEraAlonzo = "TxWitness AlonzoEra"
224-
witEra ShelleyBasedEraBabbage = "TxWitness BabbageEra"
225-
witEra ShelleyBasedEraConway = "TxWitness ConwayEra"
226-
227-
deserialiseWitnessLedgerCddl
228-
:: ShelleyBasedEra era
229-
-> TextEnvelopeCddl
186+
deserialiseWitnessLedgerCddl :: forall era .
187+
ShelleyBasedEra era
188+
-> TextEnvelope
230189
-> Either TextEnvelopeCddlError (KeyWitness era)
231-
deserialiseWitnessLedgerCddl sbe TextEnvelopeCddl{teCddlRawCBOR,teCddlDescription} =
232-
--TODO: Parse these into types because this will increase code readability and
233-
-- will make it easier to keep track of the different Cddl descriptions via
234-
-- a single sum data type.
235-
case teCddlDescription of
236-
"Key BootstrapWitness ShelleyEra" -> do
237-
w <- first TextEnvelopeCddlErrCBORDecodingError
238-
$ CBOR.decodeFullAnnotator
239-
(eraProtVerLow sbe) "Shelley Witness" CBOR.decCBOR (LBS.fromStrict teCddlRawCBOR)
240-
Right $ ShelleyBootstrapWitness sbe w
241-
"Key Witness ShelleyEra" -> do
242-
w <- first TextEnvelopeCddlErrCBORDecodingError
243-
$ CBOR.decodeFullAnnotator
244-
(eraProtVerLow sbe) "Shelley Witness" CBOR.decCBOR (LBS.fromStrict teCddlRawCBOR)
245-
Right $ ShelleyKeyWitness sbe w
246-
_ -> Left TextEnvelopeCddlUnknownKeyWitness
190+
deserialiseWitnessLedgerCddl sbe te =
191+
shelleyBasedEraConstraints sbe $ legacyDecoding te $ mapLeft textEnvelopeErrorToTextEnvelopeCddlError $
192+
deserialiseFromTextEnvelope asType te
193+
where
194+
asType :: AsType (KeyWitness era)
195+
asType = shelleyBasedEraConstraints sbe $ proxyToAsType Proxy
196+
197+
-- | This wrapper ensures that we can still decode the key witness
198+
-- that were serialized before we migrated to using 'serialiseToTextEnvelope'
199+
legacyDecoding :: TextEnvelope -> Either TextEnvelopeCddlError (KeyWitness era) -> Either TextEnvelopeCddlError (KeyWitness era)
200+
legacyDecoding TextEnvelope{teDescription, teRawCBOR} (Left (TextEnvelopeCddlErrCBORDecodingError _)) =
201+
case teDescription of
202+
"Key BootstrapWitness ShelleyEra" -> do
203+
w <- first TextEnvelopeCddlErrCBORDecodingError
204+
$ CBOR.decodeFullAnnotator
205+
(eraProtVerLow sbe) "Shelley Witness" CBOR.decCBOR (LBS.fromStrict teRawCBOR)
206+
Right $ ShelleyBootstrapWitness sbe w
207+
"Key Witness ShelleyEra" -> do
208+
w <- first TextEnvelopeCddlErrCBORDecodingError
209+
$ CBOR.decodeFullAnnotator
210+
(eraProtVerLow sbe) "Shelley Witness" CBOR.decCBOR (LBS.fromStrict teRawCBOR)
211+
Right $ ShelleyKeyWitness sbe w
212+
_ -> Left TextEnvelopeCddlUnknownKeyWitness
213+
legacyDecoding _ v = v
247214

248215
writeTxFileTextEnvelopeCddl :: ()
249216
=> ShelleyBasedEra era
@@ -280,16 +247,16 @@ data FromSomeTypeCDDL c b where
280247
FromCDDLTx
281248
:: Text -- ^ CDDL type that we want
282249
-> (InAnyShelleyBasedEra Tx -> b)
283-
-> FromSomeTypeCDDL TextEnvelopeCddl b
250+
-> FromSomeTypeCDDL TextEnvelope b
284251

285252
FromCDDLWitness
286253
:: Text -- ^ CDDL type that we want
287254
-> (InAnyShelleyBasedEra KeyWitness -> b)
288-
-> FromSomeTypeCDDL TextEnvelopeCddl b
255+
-> FromSomeTypeCDDL TextEnvelope b
289256

290257
deserialiseFromTextEnvelopeCddlAnyOf
291-
:: [FromSomeTypeCDDL TextEnvelopeCddl b]
292-
-> TextEnvelopeCddl
258+
:: [FromSomeTypeCDDL TextEnvelope b]
259+
-> TextEnvelope
293260
-> Either TextEnvelopeCddlError b
294261
deserialiseFromTextEnvelopeCddlAnyOf types teCddl =
295262
case List.find matching types of
@@ -298,21 +265,21 @@ deserialiseFromTextEnvelopeCddlAnyOf types teCddl =
298265

299266
Just (FromCDDLTx ttoken f) -> do
300267
AnyShelleyBasedEra era <- cddlTypeToEra ttoken
301-
f . InAnyShelleyBasedEra era <$> deserialiseTxLedgerCddl era teCddl
268+
f . InAnyShelleyBasedEra era <$> mapLeft textEnvelopeErrorToTextEnvelopeCddlError (deserialiseTxLedgerCddl era teCddl)
302269

303270
Just (FromCDDLWitness ttoken f) -> do
304271
AnyShelleyBasedEra era <- cddlTypeToEra ttoken
305272
f . InAnyShelleyBasedEra era <$> deserialiseWitnessLedgerCddl era teCddl
306273
where
307274
actualType :: Text
308-
actualType = teCddlType teCddl
275+
actualType = T.pack $ show $ teType teCddl
309276

310277
expectedTypes :: [Text]
311278
expectedTypes = [ typ | FromCDDLTx typ _f <- types ]
312279

313-
matching :: FromSomeTypeCDDL TextEnvelopeCddl b -> Bool
314-
matching (FromCDDLTx ttoken _f) = actualType == ttoken
315-
matching (FromCDDLWitness ttoken _f) = actualType == ttoken
280+
matching :: FromSomeTypeCDDL TextEnvelope b -> Bool
281+
matching (FromCDDLTx ttoken _f) = TextEnvelopeType (T.unpack ttoken) `legacyComparison` teType teCddl
282+
matching (FromCDDLWitness ttoken _f) = TextEnvelopeType (T.unpack ttoken) `legacyComparison` teType teCddl
316283

317284
-- Parse the text into types because this will increase code readability and
318285
-- will make it easier to keep track of the different Cddl descriptions via
@@ -340,7 +307,7 @@ cddlTypeToEra = \case
340307
unknownCddlType -> Left $ TextEnvelopeCddlErrUnknownType unknownCddlType
341308

342309
readFileTextEnvelopeCddlAnyOf
343-
:: [FromSomeTypeCDDL TextEnvelopeCddl b]
310+
:: [FromSomeTypeCDDL TextEnvelope b]
344311
-> FilePath
345312
-> IO (Either (FileError TextEnvelopeCddlError) b)
346313
readFileTextEnvelopeCddlAnyOf types path =
@@ -351,7 +318,7 @@ readFileTextEnvelopeCddlAnyOf types path =
351318

352319
readTextEnvelopeCddlFromFile
353320
:: FilePath
354-
-> IO (Either (FileError TextEnvelopeCddlError) TextEnvelopeCddl)
321+
-> IO (Either (FileError TextEnvelopeCddlError) TextEnvelope)
355322
readTextEnvelopeCddlFromFile path =
356323
runExceptT $ do
357324
bs <- fileIOExceptT path readFileBlocking

cardano-api/internal/Cardano/Api/SerialiseTextEnvelope.hs

+23-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ module Cardano.Api.SerialiseTextEnvelope
2626
, readTextEnvelopeFromFile
2727
, readTextEnvelopeOfTypeFromFile
2828
, textEnvelopeToJSON
29+
, legacyComparison
2930

3031
-- * Reading one of several key types
3132
, FromSomeType(..)
@@ -159,9 +160,29 @@ instance Error TextEnvelopeError where
159160
--
160161
expectTextEnvelopeOfType :: TextEnvelopeType -> TextEnvelope -> Either TextEnvelopeError ()
161162
expectTextEnvelopeOfType expectedType TextEnvelope { teType = actualType } =
162-
unless (expectedType == actualType) $
163+
unless (expectedType `legacyComparison` actualType) $
163164
Left (TextEnvelopeTypeError [expectedType] actualType)
164165

166+
-- | This is a backwards-compatibility patch to ensure that old envelopes
167+
-- generated by 'serialiseTxLedgerCddl' can be deserialised after switching
168+
-- to the 'serialiseToTextEnvelope'.
169+
legacyComparison :: TextEnvelopeType -> TextEnvelopeType -> Bool
170+
legacyComparison (TextEnvelopeType expectedType) (TextEnvelopeType actualType) =
171+
case (expectedType, actualType) of
172+
("TxSignedShelley", "Witnessed Tx ShelleyEra") -> True
173+
("Tx AllegraEra", "Witnessed Tx AllegraEra") -> True
174+
("Tx MaryEra", "Witnessed Tx MaryEra") -> True
175+
("Tx AlonzoEra", "Witnessed Tx AlonzoEra") -> True
176+
("Tx BabbageEra", "Witnessed Tx BabbageEra") -> True
177+
("Tx ConwayEra", "Witnessed Tx ConwayEra") -> True
178+
("TxSignedShelley", "Unwitnessed Tx ShelleyEra") -> True
179+
("Tx AllegraEra", "Unwitnessed Tx AllegraEra") -> True
180+
("Tx MaryEra", "Unwitnessed Tx MaryEra") -> True
181+
("Tx AlonzoEra", "Unwitnessed Tx AlonzoEra") -> True
182+
("Tx BabbageEra", "Unwitnessed Tx BabbageEra") -> True
183+
("Tx ConwayEra", "Unwitnessed Tx ConwayEra") -> True
184+
(expectedOther, expectedActual) -> expectedOther == expectedActual
185+
165186

166187
-- ----------------------------------------------------------------------------
167188
-- Serialisation in text envelope format
@@ -220,7 +241,7 @@ deserialiseFromTextEnvelopeAnyOf types te =
220241
expectedTypes = [ textEnvelopeType ttoken
221242
| FromSomeType ttoken _f <- types ]
222243

223-
matching (FromSomeType ttoken _f) = actualType == textEnvelopeType ttoken
244+
matching (FromSomeType ttoken _f) = textEnvelopeType ttoken `legacyComparison` actualType
224245

225246
writeFileTextEnvelope :: HasTextEnvelope a
226247
=> File content Out

cardano-api/src/Cardano/Api.hs

-2
Original file line numberDiff line numberDiff line change
@@ -679,8 +679,6 @@ module Cardano.Api (
679679
deserialiseByronTxCddl,
680680
serialiseWitnessLedgerCddl,
681681
deserialiseWitnessLedgerCddl,
682-
TextEnvelopeCddl(..), -- TODO: Deprecate this when we stop supporting the cli's
683-
-- intermediate txbody format.
684682
TextEnvelopeCddlError(..),
685683

686684
-- *** Reading one of several key types

0 commit comments

Comments
 (0)