-
Notifications
You must be signed in to change notification settings - Fork 25
Implement writeTxFileTextEnvelope and writeTxFileTextEnvelopeCanonical for SignedTx
#1033
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: master
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,62 @@ | ||
| {-# LANGUAGE DataKinds #-} | ||
| {-# LANGUAGE RankNTypes #-} | ||
| {-# LANGUAGE ScopedTypeVariables #-} | ||
| {-# LANGUAGE TypeApplications #-} | ||
|
|
||
| module Cardano.Api.Experimental.Tx.Internal.Serialise | ||
| ( writeTxFileTextEnvelope | ||
| , writeTxFileTextEnvelopeCanonical | ||
| ) | ||
| where | ||
|
|
||
| import Cardano.Api.Error | ||
| import Cardano.Api.Experimental.Era | ||
| import Cardano.Api.Experimental.Tx.Internal.Type | ||
| import Cardano.Api.IO | ||
| import Cardano.Api.Serialise.Cbor.Canonical | ||
| import Cardano.Api.Serialise.TextEnvelope.Internal | ||
|
|
||
| writeTxFileTextEnvelope | ||
| :: IsEra era | ||
| => File content Out | ||
| -> SignedTx era | ||
| -> IO (Either (FileError ()) ()) | ||
| writeTxFileTextEnvelope path = | ||
| writeLazyByteStringFile path | ||
| . serialiseTextEnvelope | ||
| . serialiseTxToTextEnvelope | ||
|
|
||
| serialiseTxToTextEnvelope :: forall era. IsEra era => SignedTx era -> TextEnvelope | ||
| serialiseTxToTextEnvelope tx' = | ||
| obtainCommonConstraints (useEra @era) $ | ||
| serialiseToTextEnvelope (Just "Ledger Cddl Format") tx' | ||
|
|
||
| -- | Write transaction in the text envelope format. The CBOR will be in canonical format according | ||
| -- to RFC 7049. It is also a requirement of CIP-21, which is not fully implemented. | ||
| -- | ||
| -- 1. RFC 7049: https://datatracker.ietf.org/doc/html/rfc7049#section-3.9 | ||
| -- 2. CIP-21: https://github.com/cardano-foundation/CIPs/blob/master/CIP-0021/README.md#canonical-cbor-serialization-format | ||
| writeTxFileTextEnvelopeCanonical | ||
| :: IsEra era | ||
| => File content Out | ||
| -> SignedTx era | ||
| -> IO (Either (FileError ()) ()) | ||
| writeTxFileTextEnvelopeCanonical path = | ||
| writeLazyByteStringFile path | ||
| . serialiseTextEnvelope | ||
| . canonicaliseTextEnvelopeCbor | ||
| . serialiseTxToTextEnvelope | ||
| where | ||
| canonicaliseTextEnvelopeCbor :: TextEnvelope -> TextEnvelope | ||
| canonicaliseTextEnvelopeCbor te = do | ||
| let canonicalisedTxBs = | ||
| either | ||
| ( \err -> | ||
| error $ | ||
| "writeTxFileTextEnvelopeCanonical: Impossible - deserialisation of just serialised bytes failed " | ||
| <> show err | ||
| ) | ||
| id | ||
| . canonicaliseCborBs | ||
| $ teRawCBOR te | ||
| te{teRawCBOR = canonicalisedTxBs} | ||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,121 @@ | ||||
| {-# LANGUAGE ConstraintKinds #-} | ||||
| {-# LANGUAGE DataKinds #-} | ||||
| {-# LANGUAGE FlexibleContexts #-} | ||||
| {-# LANGUAGE FlexibleInstances #-} | ||||
| {-# LANGUAGE GADTs #-} | ||||
| {-# LANGUAGE InstanceSigs #-} | ||||
| {-# LANGUAGE RankNTypes #-} | ||||
| {-# LANGUAGE ScopedTypeVariables #-} | ||||
| {-# LANGUAGE StandaloneDeriving #-} | ||||
| {-# LANGUAGE TypeApplications #-} | ||||
| {-# LANGUAGE TypeFamilies #-} | ||||
| {-# LANGUAGE UndecidableInstances #-} | ||||
|
|
||||
| module Cardano.Api.Experimental.Tx.Internal.Type | ||||
| ( SignedTx (..) | ||||
| , UnsignedTx (..) | ||||
| ) | ||||
| where | ||||
|
|
||||
| import Cardano.Api.Experimental.Era | ||||
| import Cardano.Api.HasTypeProxy (HasTypeProxy (..), Proxy, asType) | ||||
| import Cardano.Api.Ledger.Internal.Reexport qualified as L | ||||
| import Cardano.Api.Serialise.Cbor | ||||
| import Cardano.Api.Serialise.Raw | ||||
| ( SerialiseAsRawBytes (..) | ||||
| , SerialiseAsRawBytesError (SerialiseAsRawBytesError) | ||||
| ) | ||||
| import Cardano.Api.Serialise.TextEnvelope.Internal | ||||
|
|
||||
| import Cardano.Ledger.Binary qualified as Ledger | ||||
| import Cardano.Ledger.Core qualified as Ledger | ||||
|
|
||||
| import Control.Exception (displayException) | ||||
| import Data.Bifunctor (bimap) | ||||
| import Data.ByteString.Lazy (fromStrict) | ||||
|
|
||||
| -- | A transaction that has been witnesssed | ||||
| data SignedTx era | ||||
| = L.EraTx (LedgerEra era) => SignedTx (Ledger.Tx (LedgerEra era)) | ||||
|
|
||||
| deriving instance Eq (SignedTx era) | ||||
|
|
||||
| deriving instance Show (SignedTx era) | ||||
|
|
||||
| instance | ||||
| ( HasTypeProxy era | ||||
| , L.EraTx (LedgerEra era) | ||||
| ) | ||||
| => SerialiseAsCBOR (SignedTx era) | ||||
| where | ||||
| serialiseToCBOR (SignedTx tx) = | ||||
| Ledger.serialize' (Ledger.eraProtVerHigh @(LedgerEra era)) tx | ||||
| deserialiseFromCBOR _ = | ||||
| fmap SignedTx | ||||
| . Ledger.decodeFullAnnotator | ||||
| (Ledger.eraProtVerHigh @(LedgerEra era)) | ||||
| "UnsignedTx" | ||||
| Ledger.decCBOR | ||||
| . fromStrict | ||||
|
|
||||
| instance (L.EraTx (LedgerEra era), HasTypeProxy era) => HasTextEnvelope (SignedTx era) where | ||||
| textEnvelopeType _ = "Tx" | ||||
|
Contributor
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 may break compatibility with the old API text envelope type:
Contributor
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. Also, do you have in mind how will deserialising work without knowing the era? I guess because we have only two eras is not too problematic, but we may need two separate functions (one for each era). |
||||
|
|
||||
| instance HasTypeProxy era => HasTypeProxy (SignedTx era) where | ||||
| data AsType (SignedTx era) = AsSignedTx (AsType era) | ||||
| proxyToAsType :: Proxy (SignedTx era) -> AsType (SignedTx era) | ||||
| proxyToAsType _ = AsSignedTx (asType @era) | ||||
|
|
||||
| instance | ||||
| ( HasTypeProxy era | ||||
| , L.EraTx (LedgerEra era) | ||||
| ) | ||||
| => SerialiseAsRawBytes (SignedTx era) | ||||
| where | ||||
| serialiseToRawBytes (SignedTx tx) = | ||||
| Ledger.serialize' (Ledger.eraProtVerHigh @(LedgerEra era)) tx | ||||
| deserialiseFromRawBytes _ = | ||||
| bimap wrapError SignedTx | ||||
| . Ledger.decodeFullAnnotator | ||||
| (Ledger.eraProtVerHigh @(LedgerEra era)) | ||||
| "SignedTx" | ||||
| Ledger.decCBOR | ||||
| . fromStrict | ||||
| where | ||||
| wrapError | ||||
| :: Ledger.DecoderError -> SerialiseAsRawBytesError | ||||
| wrapError = SerialiseAsRawBytesError . displayException | ||||
|
Comment on lines
+75
to
+87
Contributor
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. I think this can probably be implemented in terms of |
||||
|
|
||||
| -- | A transaction that can contain everything | ||||
| -- except key witnesses. | ||||
| data UnsignedTx era | ||||
| = L.EraTx (LedgerEra era) => UnsignedTx (Ledger.Tx (LedgerEra era)) | ||||
|
|
||||
| instance HasTypeProxy era => HasTypeProxy (UnsignedTx era) where | ||||
| data AsType (UnsignedTx era) = AsUnsignedTx (AsType era) | ||||
| proxyToAsType :: Proxy (UnsignedTx era) -> AsType (UnsignedTx era) | ||||
| proxyToAsType _ = AsUnsignedTx (asType @era) | ||||
|
|
||||
| instance | ||||
| ( HasTypeProxy era | ||||
| , L.EraTx (LedgerEra era) | ||||
| ) | ||||
| => SerialiseAsRawBytes (UnsignedTx era) | ||||
| where | ||||
| serialiseToRawBytes (UnsignedTx tx) = | ||||
| Ledger.serialize' (Ledger.eraProtVerHigh @(LedgerEra era)) tx | ||||
| deserialiseFromRawBytes _ = | ||||
| bimap wrapError UnsignedTx | ||||
| . Ledger.decodeFullAnnotator | ||||
| (Ledger.eraProtVerHigh @(LedgerEra era)) | ||||
| "UnsignedTx" | ||||
| Ledger.decCBOR | ||||
| . fromStrict | ||||
| where | ||||
| wrapError | ||||
| :: Ledger.DecoderError -> SerialiseAsRawBytesError | ||||
| wrapError = SerialiseAsRawBytesError . displayException | ||||
|
|
||||
| deriving instance Eq (UnsignedTx era) | ||||
|
|
||||
| deriving instance Show (UnsignedTx era) | ||||
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.
You can use: first or mapLeft.