11
11
-- | Ledger CDDL Serialisation
12
12
--
13
13
module Cardano.Api.SerialiseLedgerCddl
14
- ( TextEnvelopeCddl (.. )
15
- , TextEnvelopeCddlError (.. )
14
+ ( TextEnvelopeCddlError (.. )
16
15
, FromSomeTypeCDDL (.. )
17
16
18
17
-- * Reading one of several transaction or
@@ -41,7 +40,10 @@ import Cardano.Api.Error
41
40
import Cardano.Api.HasTypeProxy
42
41
import Cardano.Api.IO
43
42
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 )
45
47
import Cardano.Api.Tx.Sign
46
48
import Cardano.Api.Utils
47
49
@@ -51,17 +53,16 @@ import qualified Cardano.Ledger.Binary as CBOR
51
53
52
54
import Control.Monad.Trans.Except.Extra (firstExceptT , handleIOExceptT , hoistEither ,
53
55
newExceptT , runExceptT )
54
- import Data.Aeson
55
56
import qualified Data.Aeson as Aeson
56
57
import Data.Aeson.Encode.Pretty (Config (.. ), defConfig , encodePretty' , keyOrder )
57
58
import Data.Bifunctor (first )
58
59
import Data.ByteString (ByteString )
59
- import qualified Data.ByteString.Base16 as Base16
60
60
import qualified Data.ByteString.Lazy as LBS
61
61
import Data.Data (Data )
62
+ import Data.Either.Combinators (mapLeft )
62
63
import qualified Data.List as List
63
64
import Data.Text (Text )
64
- import qualified Data.Text.Encoding as Text
65
+ import qualified Data.Text as T
65
66
66
67
-- Why have we gone this route? The serialization format of `TxBody era`
67
68
-- 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
77
78
-- ease removal of the non-CDDL spec serialization, we have opted to create a separate
78
79
-- data type to encompass this in the interim.
79
80
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
-
103
81
data TextEnvelopeCddlError
104
82
= TextEnvelopeCddlErrCBORDecodingError DecoderError
105
83
| TextEnvelopeCddlAesonDecodeError FilePath String
@@ -111,6 +89,13 @@ data TextEnvelopeCddlError
111
89
| TextEnvelopeCddlErrByronKeyWitnessUnsupported
112
90
deriving (Show , Eq , Data )
113
91
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
+
114
99
instance Error TextEnvelopeCddlError where
115
100
prettyError = \ case
116
101
TextEnvelopeCddlErrCBORDecodingError decoderError ->
@@ -134,36 +119,35 @@ instance Error TextEnvelopeCddlError where
134
119
TextEnvelopeCddlErrByronKeyWitnessUnsupported ->
135
120
" TextEnvelopeCddl error: Byron key witnesses are currently unsupported."
136
121
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
167
151
168
152
writeByronTxFileTextEnvelopeCddl
169
153
:: File content Out
@@ -175,75 +159,58 @@ writeByronTxFileTextEnvelopeCddl path w =
175
159
where
176
160
txJson = encodePretty' textEnvelopeCddlJSONConfig (serializeByronTx w) <> " \n "
177
161
178
- serializeByronTx :: Byron. ATxAux ByteString -> TextEnvelopeCddl
162
+ serializeByronTx :: Byron. ATxAux ByteString -> TextEnvelope
179
163
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
184
168
}
185
169
186
- deserialiseByronTxCddl :: TextEnvelopeCddl -> Either TextEnvelopeCddlError (Byron. ATxAux ByteString )
170
+ deserialiseByronTxCddl :: TextEnvelope -> Either TextEnvelopeCddlError (Byron. ATxAux ByteString )
187
171
deserialiseByronTxCddl tec =
188
172
first TextEnvelopeCddlErrCBORDecodingError $
189
173
CBOR. decodeFullAnnotatedBytes
190
174
CBOR. byronProtVer " Byron Tx"
191
- CBOR. decCBOR (LBS. fromStrict $ teCddlRawCBOR tec)
175
+ CBOR. decCBOR (LBS. fromStrict $ teRawCBOR tec)
192
176
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
208
180
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
-
214
181
genDesc :: KeyWitness era -> Text
215
182
genDesc ByronKeyWitness {} = case sbe of {}
216
183
genDesc ShelleyBootstrapWitness {} = " Key BootstrapWitness ShelleyEra"
217
184
genDesc ShelleyKeyWitness {} = " Key Witness ShelleyEra"
218
185
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
230
189
-> 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
247
214
248
215
writeTxFileTextEnvelopeCddl :: ()
249
216
=> ShelleyBasedEra era
@@ -280,16 +247,16 @@ data FromSomeTypeCDDL c b where
280
247
FromCDDLTx
281
248
:: Text -- ^ CDDL type that we want
282
249
-> (InAnyShelleyBasedEra Tx -> b )
283
- -> FromSomeTypeCDDL TextEnvelopeCddl b
250
+ -> FromSomeTypeCDDL TextEnvelope b
284
251
285
252
FromCDDLWitness
286
253
:: Text -- ^ CDDL type that we want
287
254
-> (InAnyShelleyBasedEra KeyWitness -> b )
288
- -> FromSomeTypeCDDL TextEnvelopeCddl b
255
+ -> FromSomeTypeCDDL TextEnvelope b
289
256
290
257
deserialiseFromTextEnvelopeCddlAnyOf
291
- :: [FromSomeTypeCDDL TextEnvelopeCddl b ]
292
- -> TextEnvelopeCddl
258
+ :: [FromSomeTypeCDDL TextEnvelope b ]
259
+ -> TextEnvelope
293
260
-> Either TextEnvelopeCddlError b
294
261
deserialiseFromTextEnvelopeCddlAnyOf types teCddl =
295
262
case List. find matching types of
@@ -298,21 +265,21 @@ deserialiseFromTextEnvelopeCddlAnyOf types teCddl =
298
265
299
266
Just (FromCDDLTx ttoken f) -> do
300
267
AnyShelleyBasedEra era <- cddlTypeToEra ttoken
301
- f . InAnyShelleyBasedEra era <$> deserialiseTxLedgerCddl era teCddl
268
+ f . InAnyShelleyBasedEra era <$> mapLeft textEnvelopeErrorToTextEnvelopeCddlError ( deserialiseTxLedgerCddl era teCddl)
302
269
303
270
Just (FromCDDLWitness ttoken f) -> do
304
271
AnyShelleyBasedEra era <- cddlTypeToEra ttoken
305
272
f . InAnyShelleyBasedEra era <$> deserialiseWitnessLedgerCddl era teCddl
306
273
where
307
274
actualType :: Text
308
- actualType = teCddlType teCddl
275
+ actualType = T. pack $ show $ teType teCddl
309
276
310
277
expectedTypes :: [Text ]
311
278
expectedTypes = [ typ | FromCDDLTx typ _f <- types ]
312
279
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
316
283
317
284
-- Parse the text into types because this will increase code readability and
318
285
-- will make it easier to keep track of the different Cddl descriptions via
@@ -340,7 +307,7 @@ cddlTypeToEra = \case
340
307
unknownCddlType -> Left $ TextEnvelopeCddlErrUnknownType unknownCddlType
341
308
342
309
readFileTextEnvelopeCddlAnyOf
343
- :: [FromSomeTypeCDDL TextEnvelopeCddl b ]
310
+ :: [FromSomeTypeCDDL TextEnvelope b ]
344
311
-> FilePath
345
312
-> IO (Either (FileError TextEnvelopeCddlError ) b )
346
313
readFileTextEnvelopeCddlAnyOf types path =
@@ -351,7 +318,7 @@ readFileTextEnvelopeCddlAnyOf types path =
351
318
352
319
readTextEnvelopeCddlFromFile
353
320
:: FilePath
354
- -> IO (Either (FileError TextEnvelopeCddlError ) TextEnvelopeCddl )
321
+ -> IO (Either (FileError TextEnvelopeCddlError ) TextEnvelope )
355
322
readTextEnvelopeCddlFromFile path =
356
323
runExceptT $ do
357
324
bs <- fileIOExceptT path readFileBlocking
0 commit comments