Skip to content

Commit

Permalink
Change TextView rendered format to JSON for the typed api
Browse files Browse the repository at this point in the history
  • Loading branch information
Jimbo4350 authored and intricate committed Jul 6, 2020
1 parent 36df86c commit 04944d4
Show file tree
Hide file tree
Showing 41 changed files with 244 additions and 210 deletions.
1 change: 1 addition & 0 deletions cardano-api/cardano-api.cabal
Expand Up @@ -42,6 +42,7 @@ library

build-depends: base >=4.12 && <5
, aeson
, aeson-pretty
, attoparsec
, base16-bytestring
, base58-bytestring
Expand Down
2 changes: 1 addition & 1 deletion cardano-api/src/Cardano/Api/Error.hs
Expand Up @@ -45,7 +45,7 @@ renderApiError ae =
[ Text.decodeLatin1 (unTextViewType t) | t <- expected ]
, ", but got type ", Text.decodeLatin1 (unTextViewType actual)
]

TextViewAesonDecodeError de -> sformat build de
TextViewDecodeError de -> sformat build de

textShow :: Show a => a -> Text
Expand Down
2 changes: 1 addition & 1 deletion cardano-api/src/Cardano/Api/Shelley/Address.hs
Expand Up @@ -65,7 +65,7 @@ renderAddressRole :: AddressRole -> TextViewType
renderAddressRole BootstrapAddr = "Genesis"
renderAddressRole NormalAddr = "UTxO address"

renderAddressDescr :: AddressRole -> TextViewTitle
renderAddressDescr :: AddressRole -> TextViewDescription
renderAddressDescr BootstrapAddr = "Bootstrap UTxO address"
renderAddressDescr NormalAddr = "UTxO address"

Expand Down
2 changes: 1 addition & 1 deletion cardano-api/src/Cardano/Api/Shelley/ColdKeys.hs
Expand Up @@ -203,7 +203,7 @@ renderKeyRole GenesisKey = "Genesis"
renderKeyRole GenesisUTxOKey = "Genesis UTxO"
renderKeyRole OperatorKey{} = "Node operator"

renderKeyDescr :: KeyRole -> TextViewTitle
renderKeyDescr :: KeyRole -> TextViewDescription
renderKeyDescr GenesisKey = "Genesis key"
renderKeyDescr GenesisUTxOKey = "Genesis initial UTxO key"
renderKeyDescr (OperatorKey GenesisDelegateKey) = "Genesis delegate operator key"
Expand Down
42 changes: 31 additions & 11 deletions cardano-api/src/Cardano/Api/TextView.hs
Expand Up @@ -8,7 +8,7 @@ module Cardano.Api.TextView
TextView (..)
, TextViewError (..)
, TextViewType (..)
, TextViewTitle (..)
, TextViewDescription (..)
, parseTextView
, renderTextView
, renderTextViewError
Expand All @@ -33,7 +33,10 @@ module Cardano.Api.TextView
) where

import Cardano.Prelude
import Prelude (String)

import Data.Aeson (FromJSON(..), ToJSON(..), object,
withObject, (.=), (.:))
import Data.Attoparsec.ByteString (Parser)
import qualified Data.Attoparsec.ByteString.Char8 as Atto
import qualified Data.ByteString.Base16 as Base16
Expand All @@ -53,8 +56,8 @@ newtype TextViewType
= TextViewType { unTextViewType :: ByteString }
deriving (Eq, IsString, Show, Semigroup)

newtype TextViewTitle
= TextViewTitle { unTextViewTitle :: ByteString }
newtype TextViewDescription
= TextViewDescription { unTextViewDescription :: ByteString }
deriving (Eq, IsString, Show, Semigroup)

-- | A 'TextView' is a structured envalope for serialised binary values
Expand All @@ -69,16 +72,31 @@ newtype TextViewTitle
--
data TextView = TextView
{ tvType :: !TextViewType
, tvTitle :: !TextViewTitle
, tvDescription :: !TextViewDescription
, tvRawCBOR :: !ByteString
} deriving (Eq, Show)

instance ToJSON TextView where
toJSON (TextView (TextViewType tvType) (TextViewDescription desc) rawCBOR) =
object [ "type" .= Text.decodeUtf8 tvType
, "description" .= Text.decodeUtf8 desc
, "cborHex" .= (Text.decodeUtf8 $ Base16.encode rawCBOR)
]

instance FromJSON TextView where
parseJSON = withObject "TextView" $ \v -> TextView
<$> (TextViewType . Text.encodeUtf8 <$> v .: "type")
<*> (TextViewDescription . Text.encodeUtf8 <$> v .: "description")
<*> (fst . Base16.decode . Text.encodeUtf8 <$> v .: "cborHex")


-- | The errors that the pure 'TextView' parsing\/decoding functions can return.
--
data TextViewError
= TextViewFormatError !Text
| TextViewTypeError ![TextViewType] !TextViewType -- ^ expected, actual
| TextViewDecodeError !DecoderError
| TextViewAesonDecodeError !String
deriving (Eq, Show)

renderTextViewError :: TextViewError -> Text
Expand All @@ -97,14 +115,16 @@ renderTextViewError tve =
<> Text.intercalate ", "
[ Text.decodeLatin1 (unTextViewType expType) | expType <- expTypes ]
<> " Actual: " <> (Text.decodeLatin1 (unTextViewType actType))

TextViewAesonDecodeError decErr -> "TextView aeson decode error: " <> textShow decErr
TextViewDecodeError decErr -> "TextView decode error: " <> textShow decErr

-- | Parse a 'TextView' from the external serialised format.
--
-- TODO: Do not use this to parse TextView as TextView is now serialized to JSON
-- Need to remove once the old api has been removed
parseTextView :: ByteString -> Either TextViewError TextView
parseTextView =
first (TextViewFormatError . Text.pack) . Atto.parseOnly pTextView
first (\str -> TextViewFormatError . Text.pack $ "Cardano.Api.TextView.parseTextView: " ++ str) . Atto.parseOnly pTextView


-- | Render a 'TextView' into the external serialised format.
Expand All @@ -113,7 +133,7 @@ renderTextView :: TextView -> ByteString
renderTextView tv =
BS.unlines $
[ "type: " <> unTextViewType (tvType tv)
, "title: " <> unTextViewTitle (tvTitle tv)
, "title: " <> unTextViewDescription (tvDescription tv)
, "cbor-hex:"
]
<> rawToMultilineHex (tvRawCBOR tv)
Expand Down Expand Up @@ -159,12 +179,12 @@ decodeFromTextView decoder tv =
-- | Encode a value to a 'TextView' using a CBOR encoder. The type and title
-- fields must also be specified.
--
encodeToTextView :: TextViewType -> TextViewTitle -> (a -> Encoding)
encodeToTextView :: TextViewType -> TextViewDescription -> (a -> Encoding)
-> a -> TextView
encodeToTextView tvType tvTitle encode a =
encodeToTextView tvType tvDescription encode a =
TextView
{ tvType
, tvTitle
, tvDescription
, tvRawCBOR = serializeEncoding' (encode a)
}

Expand Down Expand Up @@ -257,7 +277,7 @@ pTextView = do
title <- Atto.string "title: " *> Atto.takeWhile (/= '\n') <* Atto.endOfLine
hex <- Atto.string "cbor-hex:\n" *> Atto.takeByteString <* Atto.endOfInput
case Base16.decode . BS.concat . map (BS.dropWhile isSpace) $ BS.lines hex of
(raw, "") -> pure $ TextView (TextViewType typ) (TextViewTitle title) raw
(raw, "") -> pure $ TextView (TextViewType typ) (TextViewDescription title) raw
(_, err) -> panic $ "pTextView: Base16.deocde failed on " <> textShow err

-- | Convert a raw ByteString to hexadecimal and then line wrap
Expand Down
36 changes: 28 additions & 8 deletions cardano-api/src/Cardano/Api/Typed.hs
Expand Up @@ -204,6 +204,7 @@ module Cardano.Api.Typed (
serialiseToTextEnvelope,
deserialiseFromTextEnvelope,
readFileTextEnvelope,
readFileTextEnvelopeOfType,
writeFileTextEnvelope,
-- *** Reading one of several key types
FromSomeType(..),
Expand Down Expand Up @@ -282,6 +283,7 @@ module Cardano.Api.Typed (

import Prelude

import Data.Aeson.Encode.Pretty (encodePretty)
import Data.Proxy (Proxy(..))
import Data.Kind (Constraint)
import Data.Void (Void)
Expand Down Expand Up @@ -319,7 +321,7 @@ import qualified Codec.Binary.Bech32 as Bech32
import Control.Applicative
import Control.Monad
--import Control.Monad.IO.Class
--import Control.Monad.Trans.Except
import Control.Monad.Trans.Except (ExceptT(..))
import Control.Monad.Trans.Except.Extra
import Control.Exception (Exception(..), IOException, throwIO)
import Control.Tracer (nullTracer)
Expand Down Expand Up @@ -2414,7 +2416,7 @@ class HasTypeProxy addr => SerialiseAddress addr where

type TextEnvelope = TextView.TextView
type TextEnvelopeType = TextView.TextViewType
type TextEnvelopeDescr = TextView.TextViewTitle
type TextEnvelopeDescr = TextView.TextViewDescription

class SerialiseAsCBOR a => HasTextEnvelope a where
textEnvelopeType :: AsType a -> TextEnvelopeType
Expand Down Expand Up @@ -2442,7 +2444,7 @@ serialiseToTextEnvelope :: forall a. HasTextEnvelope a
serialiseToTextEnvelope mbDescr a =
TextView.TextView {
TextView.tvType = textEnvelopeType ttoken
, TextView.tvTitle = fromMaybe (textEnvelopeDefaultDescr a) mbDescr
, TextView.tvDescription = fromMaybe (textEnvelopeDefaultDescr a) mbDescr
, TextView.tvRawCBOR = serialiseToCBOR a
}
where
Expand All @@ -2457,7 +2459,7 @@ deserialiseFromTextEnvelope :: HasTextEnvelope a
deserialiseFromTextEnvelope ttoken te = do
TextView.expectTextViewOfType (textEnvelopeType ttoken) te
first TextView.TextViewDecodeError $
deserialiseFromCBOR ttoken (TextView.tvRawCBOR te)
deserialiseFromCBOR ttoken (TextView.tvRawCBOR te) --TODO: You have switched from CBOR to JSON

data FromSomeType (c :: * -> Constraint) b where
FromSomeType :: c a => AsType a -> (a -> b) -> FromSomeType c b
Expand Down Expand Up @@ -2491,8 +2493,7 @@ writeFileTextEnvelope path mbDescr a =
runExceptT $ do
handleIOExceptT (FileIOError path) $ BS.writeFile path content
where
content = TextView.renderTextView (serialiseToTextEnvelope mbDescr a)

content = LBS.toStrict $ encodePretty (serialiseToTextEnvelope mbDescr a)

readFileTextEnvelope :: HasTextEnvelope a
=> AsType a
Expand All @@ -2502,7 +2503,7 @@ readFileTextEnvelope ttoken path =
runExceptT $ do
content <- handleIOExceptT (FileIOError path) $ BS.readFile path
firstExceptT (FileError path) $ hoistEither $ do
te <- TextView.parseTextView content
te <- first TextView.TextViewAesonDecodeError $ Aeson.eitherDecodeStrict' content
deserialiseFromTextEnvelope ttoken te


Expand All @@ -2513,9 +2514,28 @@ readFileTextEnvelopeAnyOf types path =
runExceptT $ do
content <- handleIOExceptT (FileIOError path) $ BS.readFile path
firstExceptT (FileError path) $ hoistEither $ do
te <- TextView.parseTextView content
te <- first TextView.TextViewAesonDecodeError $ Aeson.eitherDecodeStrict content
deserialiseFromTextEnvelopeAnyOf types te

readFileTextEnvelopeOfType
:: TextEnvelopeType
-> FilePath
-> IO (Either (FileError TextEnvelopeError) TextEnvelope)
readFileTextEnvelopeOfType expectedType path =
runExceptT $ do
te <- ExceptT readTextEnvelope
firstExceptT (FileError path) $ hoistEither $
TextView.expectTextViewOfType expectedType te
return te
where
readTextEnvelope :: IO (Either (FileError TextEnvelopeError) TextEnvelope)
readTextEnvelope =
runExceptT $ do
bs <- handleIOExceptT (FileIOError path) $
BS.readFile path
firstExceptT (FileError path . TextView.TextViewAesonDecodeError)
. hoistEither $ Aeson.eitherDecodeStrict' bs


-- ----------------------------------------------------------------------------
-- Error reporting
Expand Down
2 changes: 1 addition & 1 deletion cardano-api/test/Test/Cardano/Api/Gen.hs
Expand Up @@ -491,5 +491,5 @@ genTextView :: Gen TextView
genTextView =
TextView
<$> fmap TextViewType (Gen.utf8 (Range.linear 1 20) Gen.alpha)
<*> fmap TextViewTitle (Gen.utf8 (Range.linear 1 80) (Gen.filter (/= '\n') Gen.ascii))
<*> fmap TextViewDescription (Gen.utf8 (Range.linear 1 80) (Gen.filter (/= '\n') Gen.ascii))
<*> Gen.bytes (Range.linear 0 500)
8 changes: 4 additions & 4 deletions cardano-cli/src/Cardano/CLI/Shelley/Run/Address.hs
Expand Up @@ -15,7 +15,7 @@ import Control.Monad.Trans.Except (ExceptT)
import Control.Monad.Trans.Except.Extra (firstExceptT, newExceptT)

import Cardano.Api
import Cardano.Api.TextView (TextViewTitle (..))
import Cardano.Api.TextView (TextViewDescription (..))
import qualified Cardano.Api.Typed as Api (NetworkId (..))
import Cardano.Api.Typed (AsType (..), Error (..), FileError,
Key (..), PaymentCredential (..), StakeCredential (..),
Expand Down Expand Up @@ -65,9 +65,9 @@ runAddressKeyGen (VerificationKeyFile vkeyPath) (SigningKeyFile skeyPath) = do
. newExceptT
$ writeFileTextEnvelope vkeyPath (Just vkeyDesc) vkey
where
skeyDesc, vkeyDesc :: TextViewTitle
skeyDesc = TextViewTitle "Payment Signing Key"
vkeyDesc = TextViewTitle "Payment Verification Key"
skeyDesc, vkeyDesc :: TextViewDescription
skeyDesc = TextViewDescription "Payment Signing Key"
vkeyDesc = TextViewDescription "Payment Verification Key"

runAddressKeyHash :: VerificationKeyFile -> Maybe OutputFile -> ExceptT ShelleyAddressCmdError IO ()
runAddressKeyHash (VerificationKeyFile vkeyPath) mOutputFp = do
Expand Down
32 changes: 16 additions & 16 deletions cardano-cli/src/Cardano/CLI/Shelley/Run/Genesis.hs
Expand Up @@ -36,9 +36,9 @@ import Cardano.Api.Shelley.Genesis
import Ouroboros.Consensus.BlockchainTime (SystemStart (..))
import Ouroboros.Consensus.Shelley.Protocol (TPraosStandardCrypto)

import qualified Shelley.Spec.Ledger.Coin as Ledger
import qualified Shelley.Spec.Ledger.Address as Ledger
import qualified Shelley.Spec.Ledger.Keys as Ledger
import qualified Shelley.Spec.Ledger.Coin as Ledger
import qualified Shelley.Spec.Ledger.Keys as Ledger

import Cardano.CLI.Shelley.Commands
import Cardano.CLI.Shelley.Parsers (renderTxIn)
Expand Down Expand Up @@ -110,9 +110,9 @@ runGenesisKeyGenGenesis (VerificationKeyFile vkeyPath)
. newExceptT
$ writeFileTextEnvelope vkeyPath (Just vkeyDesc) vkey
where
skeyDesc, vkeyDesc :: TextViewTitle
skeyDesc = TextViewTitle "Genesis Signing Key"
vkeyDesc = TextViewTitle "Genesis Verification Key"
skeyDesc, vkeyDesc :: TextViewDescription
skeyDesc = TextViewDescription "Genesis Signing Key"
vkeyDesc = TextViewDescription "Genesis Verification Key"


runGenesisKeyGenDelegate :: VerificationKeyFile
Expand All @@ -132,15 +132,15 @@ runGenesisKeyGenDelegate (VerificationKeyFile vkeyPath)
$ writeFileTextEnvelope vkeyPath (Just vkeyDesc) vkey
firstExceptT ShelleyGenesisCmdWriteFileError
. newExceptT
$ writeFileTextEnvelope ocertCtrPath (Just ocertCtrDesc)
$ writeFileTextEnvelope ocertCtrPath (Just certCtrDesc)
$ OperationalCertificateIssueCounter
initialCounter
(castVerificationKey vkey) -- Cast to a 'StakePoolKey'
where
skeyDesc, vkeyDesc, ocertCtrDesc :: TextViewTitle
skeyDesc = TextViewTitle "Genesis delegate operator key"
vkeyDesc = TextViewTitle "Genesis delegate operator key"
ocertCtrDesc = TextViewTitle $ "Next certificate issue number: " <> BS.pack (show initialCounter)
skeyDesc, vkeyDesc, certCtrDesc :: TextViewDescription
skeyDesc = TextViewDescription "Genesis delegate operator key"
vkeyDesc = TextViewDescription "Genesis delegate operator key"
certCtrDesc = TextViewDescription $ "Next certificate issue number: " <> BS.pack (show initialCounter)

initialCounter :: Natural
initialCounter = 0
Expand All @@ -159,9 +159,9 @@ runGenesisKeyGenDelegateVRF (VerificationKeyFile vkeyPath)
. newExceptT
$ writeFileTextEnvelope vkeyPath (Just vkeyDesc) vkey
where
skeyDesc, vkeyDesc :: TextViewTitle
skeyDesc = TextViewTitle "VRF Signing Key"
vkeyDesc = TextViewTitle "VRF Verification Key"
skeyDesc, vkeyDesc :: TextViewDescription
skeyDesc = TextViewDescription "VRF Signing Key"
vkeyDesc = TextViewDescription "VRF Verification Key"


runGenesisKeyGenUTxO :: VerificationKeyFile -> SigningKeyFile
Expand All @@ -177,9 +177,9 @@ runGenesisKeyGenUTxO (VerificationKeyFile vkeyPath)
. newExceptT
$ writeFileTextEnvelope vkeyPath (Just vkeyDesc) vkey
where
skeyDesc, vkeyDesc :: TextViewTitle
skeyDesc = TextViewTitle "Genesis Initial UTxO Signing Key"
vkeyDesc = TextViewTitle "Genesis Initial UTxO Verification Key"
skeyDesc, vkeyDesc :: TextViewDescription
skeyDesc = TextViewDescription "Genesis Initial UTxO Signing Key"
vkeyDesc = TextViewDescription "Genesis Initial UTxO Verification Key"


runGenesisKeyHash :: VerificationKeyFile -> ExceptT ShelleyGenesisCmdError IO ()
Expand Down
6 changes: 3 additions & 3 deletions cardano-cli/src/Cardano/CLI/Shelley/Run/Governance.hs
Expand Up @@ -13,7 +13,7 @@ import Control.Monad.Trans.Except.Extra (firstExceptT, left, right,
newExceptT)

import Cardano.Api (EpochNo, textShow)
import Cardano.Api.TextView (TextViewTitle (..))
import Cardano.Api.TextView (TextViewDescription (..))
import Cardano.Api.Typed (AsType (..), Error (..), FileError,
Lovelace, StakeCredential (..), TextEnvelopeError,
makeMIRCertificate, verificationKeyHash,
Expand Down Expand Up @@ -77,8 +77,8 @@ runGovernanceMIRCertificate mirPot vKeys rwdAmts (OutputFile oFp) = do
. newExceptT
$ writeFileTextEnvelope oFp (Just mirCertDesc) mirCert
where
mirCertDesc :: TextViewTitle
mirCertDesc = TextViewTitle "Move Instantaneous Rewards Certificate"
mirCertDesc :: TextViewDescription
mirCertDesc = TextViewDescription "Move Instantaneous Rewards Certificate"

checkEqualKeyRewards :: [VerificationKeyFile] -> [Lovelace] -> ExceptT ShelleyGovernanceError IO ()
checkEqualKeyRewards keys rwds = do
Expand Down

0 comments on commit 04944d4

Please sign in to comment.