Skip to content

Commit

Permalink
Add eitherDeserialiseFromRawBytes method to SerialiseAsRawBytes type …
Browse files Browse the repository at this point in the history
…class

More descriptive error message for decode of AssetName
Introduce new SerialiseAsRawBytesError error type
  • Loading branch information
newhoggy committed Dec 11, 2022
1 parent 2766947 commit 9b9df9b
Show file tree
Hide file tree
Showing 27 changed files with 276 additions and 202 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/haskell.yml
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@ jobs:
# - name: Setup tmate session
# if: ${{ failure() }}
# uses: mxschmitt/action-tmate@v3
# with:
# limit-access-to-actor: true

release:
needs: [build]
Expand Down
1 change: 1 addition & 0 deletions cardano-api/cardano-api.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ library
, cryptonite
, deepseq
, directory
, either
, filepath
, formatting
, iproute
Expand Down
2 changes: 1 addition & 1 deletion cardano-api/src/Cardano/Api.hs
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ module Cardano.Api (
-- | Some types have a natural raw binary format.
SerialiseAsRawBytes,
serialiseToRawBytes,
deserialiseFromRawBytes,
eitherDeserialiseFromRawBytes,
serialiseToRawBytesHex,
deserialiseFromRawBytesHex,
serialiseToRawBytesHexText,
Expand Down
49 changes: 26 additions & 23 deletions cardano-api/src/Cardano/Api/Address.hs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ import Prelude
import Control.Applicative ((<|>))
import Data.Aeson (FromJSON (..), ToJSON (..), withText, (.=))
import qualified Data.Aeson as Aeson
import Data.Bifunctor (first)
import qualified Data.ByteString.Base58 as Base58
import Data.Char (isAsciiLower, isAsciiUpper, isDigit)
import Data.Either.Combinators (rightToMaybe)
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
Expand Down Expand Up @@ -221,22 +223,22 @@ instance SerialiseAsRawBytes (Address ByronAddr) where
. Shelley.BootstrapAddress
$ addr

deserialiseFromRawBytes (AsAddress AsByronAddr) bs =
eitherDeserialiseFromRawBytes (AsAddress AsByronAddr) bs =
case Shelley.deserialiseAddr bs :: Maybe (Shelley.Addr StandardCrypto) of
Nothing -> Nothing
Just Shelley.Addr{} -> Nothing
Nothing -> Left (SerialiseAsRawBytesError "Unable to deserialise Address ByronAddr")
Just Shelley.Addr{} -> Left (SerialiseAsRawBytesError "Unable to deserialise Address ByronAddr")
Just (Shelley.AddrBootstrap (Shelley.BootstrapAddress addr)) ->
Just (ByronAddress addr)
Right (ByronAddress addr)

instance SerialiseAsRawBytes (Address ShelleyAddr) where
serialiseToRawBytes (ShelleyAddress nw pc scr) =
Shelley.serialiseAddr (Shelley.Addr nw pc scr)

deserialiseFromRawBytes (AsAddress AsShelleyAddr) bs =
eitherDeserialiseFromRawBytes (AsAddress AsShelleyAddr) bs =
case Shelley.deserialiseAddr bs of
Nothing -> Nothing
Just Shelley.AddrBootstrap{} -> Nothing
Just (Shelley.Addr nw pc scr) -> Just (ShelleyAddress nw pc scr)
Nothing -> Left (SerialiseAsRawBytesError "Unable to deserialise bootstrap Address ShelleyAddr")
Just Shelley.AddrBootstrap{} -> Left (SerialiseAsRawBytesError "Unable to deserialise bootstrap Address ShelleyAddr")
Just (Shelley.Addr nw pc scr) -> Right (ShelleyAddress nw pc scr)

instance SerialiseAsBech32 (Address ShelleyAddr) where
bech32PrefixFor (ShelleyAddress Shelley.Mainnet _ _) = "addr"
Expand All @@ -254,7 +256,7 @@ instance SerialiseAddress (Address ByronAddr) where

deserialiseAddress (AsAddress AsByronAddr) txt = do
bs <- Base58.decodeBase58 Base58.bitcoinAlphabet (Text.encodeUtf8 txt)
deserialiseFromRawBytes (AsAddress AsByronAddr) bs
rightToMaybe (eitherDeserialiseFromRawBytes (AsAddress AsByronAddr) bs)

instance SerialiseAddress (Address ShelleyAddr) where
serialiseAddress addr@ShelleyAddress{} =
Expand Down Expand Up @@ -327,14 +329,14 @@ instance SerialiseAsRawBytes AddressAny where
serialiseToRawBytes (AddressByron addr) = serialiseToRawBytes addr
serialiseToRawBytes (AddressShelley addr) = serialiseToRawBytes addr

deserialiseFromRawBytes AsAddressAny bs =
eitherDeserialiseFromRawBytes AsAddressAny bs =
case Shelley.deserialiseAddr bs of
Nothing -> Nothing
Nothing -> Left (SerialiseAsRawBytesError "Unable to deserialise AddressAny")
Just (Shelley.AddrBootstrap (Shelley.BootstrapAddress addr)) ->
Just (AddressByron (ByronAddress addr))
Right (AddressByron (ByronAddress addr))

Just (Shelley.Addr nw pc scr) ->
Just (AddressShelley (ShelleyAddress nw pc scr))
Right (AddressShelley (ShelleyAddress nw pc scr))

instance SerialiseAddress AddressAny where
serialiseAddress (AddressByron addr) = serialiseAddress addr
Expand Down Expand Up @@ -453,8 +455,9 @@ instance (IsCardanoEra era, Typeable era) => SerialiseAsRawBytes (AddressInEra e
serialiseToRawBytes (AddressInEra ShelleyAddressInEra{} addr) =
serialiseToRawBytes addr

deserialiseFromRawBytes _ bs =
anyAddressInEra cardanoEra =<< deserialiseFromRawBytes AsAddressAny bs
eitherDeserialiseFromRawBytes _ bs =
first (const (SerialiseAsRawBytesError "Unable to deserialise AddressInEra era")) $
anyAddressInEra cardanoEra =<< first unSerialiseAsRawBytesError (eitherDeserialiseFromRawBytes AsAddressAny bs)

instance IsCardanoEra era => SerialiseAddress (AddressInEra era) where
serialiseAddress (AddressInEra ByronAddressInAnyEra addr) =
Expand All @@ -464,7 +467,7 @@ instance IsCardanoEra era => SerialiseAddress (AddressInEra era) where
serialiseAddress addr

deserialiseAddress _ t =
anyAddressInEra cardanoEra =<< deserialiseAddress AsAddressAny t
rightToMaybe . anyAddressInEra cardanoEra =<< deserialiseAddress AsAddressAny t

instance EraCast (AddressTypeInEra addrtype) where
eraCast toEra' v = case v of
Expand All @@ -491,14 +494,14 @@ anyAddressInShelleyBasedEra (AddressShelley addr) = shelleyAddressInEra addr

anyAddressInEra :: CardanoEra era
-> AddressAny
-> Maybe (AddressInEra era)
-> Either String (AddressInEra era)
anyAddressInEra _ (AddressByron addr) =
Just (AddressInEra ByronAddressInAnyEra addr)
Right (AddressInEra ByronAddressInAnyEra addr)

anyAddressInEra era (AddressShelley addr) =
case cardanoEraStyle era of
LegacyByronEra -> Nothing
ShelleyBasedEra era' -> Just (AddressInEra (ShelleyAddressInEra era') addr)
LegacyByronEra -> Left "Expected Byron based era address"
ShelleyBasedEra era' -> Right (AddressInEra (ShelleyAddressInEra era') addr)

toAddressAny :: Address addr -> AddressAny
toAddressAny a@ShelleyAddress{} = AddressShelley a
Expand Down Expand Up @@ -571,10 +574,10 @@ instance SerialiseAsRawBytes StakeAddress where
serialiseToRawBytes (StakeAddress nw sc) =
Shelley.serialiseRewardAcnt (Shelley.RewardAcnt nw sc)

deserialiseFromRawBytes AsStakeAddress bs =
eitherDeserialiseFromRawBytes AsStakeAddress bs =
case Shelley.deserialiseRewardAcnt bs of
Nothing -> Nothing
Just (Shelley.RewardAcnt nw sc) -> Just (StakeAddress nw sc)
Nothing -> Left (SerialiseAsRawBytesError "Unable to deserialise StakeAddress")
Just (Shelley.RewardAcnt nw sc) -> Right (StakeAddress nw sc)


instance SerialiseAsBech32 StakeAddress where
Expand Down
6 changes: 3 additions & 3 deletions cardano-api/src/Cardano/Api/Block.hs
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,9 @@ newtype instance Hash BlockHeader = HeaderHash SBS.ShortByteString
instance SerialiseAsRawBytes (Hash BlockHeader) where
serialiseToRawBytes (HeaderHash bs) = SBS.fromShort bs

deserialiseFromRawBytes (AsHash AsBlockHeader) bs
| BS.length bs == 32 = Just $! HeaderHash (SBS.toShort bs)
| otherwise = Nothing
eitherDeserialiseFromRawBytes (AsHash AsBlockHeader) bs
| BS.length bs == 32 = Right $! HeaderHash (SBS.toShort bs)
| otherwise = Left (SerialiseAsRawBytesError "Unable to deserialise Hash BlockHeader")

instance HasTypeProxy BlockHeader where
data AsType BlockHeader = AsBlockHeader
Expand Down
6 changes: 3 additions & 3 deletions cardano-api/src/Cardano/Api/Key.hs
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ generateInsecureSigningKey
-> IO (SigningKey keyrole, StdGen)
generateInsecureSigningKey g keytype = do
let (bs, g') = Random.genByteString (fromIntegral $ deterministicSigningKeySeedSize keytype) g
case deserialiseFromRawBytes (AsSigningKey keytype) bs of
Just key -> return (key, g')
Nothing -> error "generateInsecureSigningKey: Unable to generate insecure key"
case eitherDeserialiseFromRawBytes (AsSigningKey keytype) bs of
Right key -> return (key, g')
Left (SerialiseAsRawBytesError msg) -> error $ "generateInsecureSigningKey: Unable to generate insecure key: " <> msg

instance HasTypeProxy a => HasTypeProxy (VerificationKey a) where
data AsType (VerificationKey a) = AsVerificationKey (AsType a)
Expand Down
38 changes: 21 additions & 17 deletions cardano-api/src/Cardano/Api/KeysByron.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ import Prelude
import qualified Codec.CBOR.Decoding as CBOR
import qualified Codec.CBOR.Read as CBOR
import Control.Monad
import Data.Bifunctor
import qualified Data.ByteString.Lazy as LB
import Data.Either.Combinators
import Data.String (IsString)
import Data.Text (Text)
import qualified Data.Text as Text
Expand All @@ -52,8 +54,8 @@ import qualified Cardano.Crypto.Hashing as Byron
import qualified Cardano.Crypto.Signing as Byron
import qualified Cardano.Crypto.Wallet as Wallet

import Cardano.Api.HasTypeProxy
import Cardano.Api.Hash
import Cardano.Api.HasTypeProxy
import Cardano.Api.Key
import Cardano.Api.KeysShelley
import Cardano.Api.SerialiseCBOR
Expand Down Expand Up @@ -140,17 +142,17 @@ instance SerialiseAsRawBytes (VerificationKey ByronKey) where
serialiseToRawBytes (ByronVerificationKey (Byron.VerificationKey xvk)) =
Crypto.HD.unXPub xvk

deserialiseFromRawBytes (AsVerificationKey AsByronKey) bs =
either (const Nothing) (Just . ByronVerificationKey . Byron.VerificationKey)
(Crypto.HD.xpub bs)
eitherDeserialiseFromRawBytes (AsVerificationKey AsByronKey) bs =
first (\msg -> SerialiseAsRawBytesError ("Unable to deserialise VerificationKey ByronKey" ++ msg)) $
ByronVerificationKey . Byron.VerificationKey <$> Crypto.HD.xpub bs

instance SerialiseAsRawBytes (SigningKey ByronKey) where
serialiseToRawBytes (ByronSigningKey (Byron.SigningKey xsk)) =
toStrictByteString $ Crypto.toCBORXPrv xsk

deserialiseFromRawBytes (AsSigningKey AsByronKey) bs =
either (const Nothing) (Just . ByronSigningKey . Byron.SigningKey)
(snd <$> CBOR.deserialiseFromBytes Byron.fromCBORXPrv (LB.fromStrict bs))
eitherDeserialiseFromRawBytes (AsSigningKey AsByronKey) bs =
first (\e -> SerialiseAsRawBytesError ("Unable to deserialise SigningKey ByronKey" ++ show e)) $
ByronSigningKey . Byron.SigningKey . snd <$> CBOR.deserialiseFromBytes Byron.fromCBORXPrv (LB.fromStrict bs)

newtype instance Hash ByronKey = ByronKeyHash Byron.KeyHash
deriving (Eq, Ord)
Expand All @@ -162,8 +164,9 @@ instance SerialiseAsRawBytes (Hash ByronKey) where
serialiseToRawBytes (ByronKeyHash (Byron.KeyHash vkh)) =
Byron.abstractHashToBytes vkh

deserialiseFromRawBytes (AsHash AsByronKey) bs =
ByronKeyHash . Byron.KeyHash <$> Byron.abstractHashFromBytes bs
eitherDeserialiseFromRawBytes (AsHash AsByronKey) bs =
maybeToRight (SerialiseAsRawBytesError "Unable to deserialise Hash ByronKey") $
ByronKeyHash . Byron.KeyHash <$> Byron.abstractHashFromBytes bs

instance CastVerificationKeyRole ByronKey PaymentExtendedKey where
castVerificationKey (ByronVerificationKey vk) =
Expand Down Expand Up @@ -233,24 +236,25 @@ instance SerialiseAsRawBytes (Hash ByronKeyLegacy) where
serialiseToRawBytes (ByronKeyHashLegacy (Byron.KeyHash vkh)) =
Byron.abstractHashToBytes vkh

deserialiseFromRawBytes (AsHash AsByronKeyLegacy) bs =
ByronKeyHashLegacy . Byron.KeyHash <$> Byron.abstractHashFromBytes bs
eitherDeserialiseFromRawBytes (AsHash AsByronKeyLegacy) bs =
maybeToRight (SerialiseAsRawBytesError "Unable to deserialise Hash ByronKeyLegacy") $
ByronKeyHashLegacy . Byron.KeyHash <$> Byron.abstractHashFromBytes bs

instance SerialiseAsRawBytes (VerificationKey ByronKeyLegacy) where
serialiseToRawBytes (ByronVerificationKeyLegacy (Byron.VerificationKey xvk)) =
Crypto.HD.unXPub xvk

deserialiseFromRawBytes (AsVerificationKey AsByronKeyLegacy) bs =
either (const Nothing) (Just . ByronVerificationKeyLegacy . Byron.VerificationKey)
(Crypto.HD.xpub bs)
eitherDeserialiseFromRawBytes (AsVerificationKey AsByronKeyLegacy) bs =
first (\msg -> SerialiseAsRawBytesError ("Unable to deserialise VerificationKey ByronKeyLegacy" ++ msg)) $
ByronVerificationKeyLegacy . Byron.VerificationKey <$> Crypto.HD.xpub bs

instance SerialiseAsRawBytes (SigningKey ByronKeyLegacy) where
serialiseToRawBytes (ByronSigningKeyLegacy (Byron.SigningKey xsk)) =
Crypto.HD.unXPrv xsk

deserialiseFromRawBytes (AsSigningKey AsByronKeyLegacy) bs =
either (const Nothing) (Just . ByronSigningKeyLegacy . snd)
(CBOR.deserialiseFromBytes decodeLegacyDelegateKey $ LB.fromStrict bs)
eitherDeserialiseFromRawBytes (AsSigningKey AsByronKeyLegacy) bs =
first (\e -> SerialiseAsRawBytesError ("Unable to deserialise SigningKey ByronKeyLegacy" ++ show e)) $
ByronSigningKeyLegacy . snd <$> CBOR.deserialiseFromBytes decodeLegacyDelegateKey (LB.fromStrict bs)
where
-- Stolen from: cardano-sl/binary/src/Pos/Binary/Class/Core.hs
-- | Enforces that the input size is the same as the decoded one, failing in
Expand Down
37 changes: 21 additions & 16 deletions cardano-api/src/Cardano/Api/KeysPraos.hs
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,26 @@ module Cardano.Api.KeysPraos (

import Prelude

import Data.Either.Combinators (maybeToRight)
import Data.String (IsString (..))

import qualified Cardano.Crypto.DSIGN.Class as Crypto
import qualified Cardano.Crypto.Hash.Class as Crypto
import qualified Cardano.Crypto.KES.Class as Crypto
import qualified Cardano.Crypto.VRF.Class as Crypto
import Cardano.Ledger.Crypto (StandardCrypto)
import qualified Cardano.Ledger.Crypto as Shelley (KES, VRF)
import qualified Cardano.Ledger.Keys as Shelley
import Cardano.Ledger.Crypto (StandardCrypto)

import Cardano.Api.HasTypeProxy
import Cardano.Api.Hash
import Cardano.Api.HasTypeProxy
import Cardano.Api.Key
import Cardano.Api.SerialiseBech32
import Cardano.Api.SerialiseCBOR
import Cardano.Api.SerialiseRaw
import Cardano.Api.SerialiseTextEnvelope
import Cardano.Api.SerialiseUsing


--
-- KES keys
--
Expand Down Expand Up @@ -94,16 +94,17 @@ instance SerialiseAsRawBytes (VerificationKey KesKey) where
serialiseToRawBytes (KesVerificationKey vk) =
Crypto.rawSerialiseVerKeyKES vk

deserialiseFromRawBytes (AsVerificationKey AsKesKey) bs =
KesVerificationKey <$>
Crypto.rawDeserialiseVerKeyKES bs
eitherDeserialiseFromRawBytes (AsVerificationKey AsKesKey) bs =
maybeToRight (SerialiseAsRawBytesError "Unable to deserialise VerificationKey KesKey") $
KesVerificationKey <$> Crypto.rawDeserialiseVerKeyKES bs

instance SerialiseAsRawBytes (SigningKey KesKey) where
serialiseToRawBytes (KesSigningKey sk) =
Crypto.rawSerialiseSignKeyKES sk

deserialiseFromRawBytes (AsSigningKey AsKesKey) bs =
KesSigningKey <$> Crypto.rawDeserialiseSignKeyKES bs
eitherDeserialiseFromRawBytes (AsSigningKey AsKesKey) bs =
maybeToRight (SerialiseAsRawBytesError "Unable to deserialise SigningKey KesKey") $
KesSigningKey <$> Crypto.rawDeserialiseSignKeyKES bs

instance SerialiseAsBech32 (VerificationKey KesKey) where
bech32PrefixFor _ = "kes_vk"
Expand All @@ -126,8 +127,9 @@ instance SerialiseAsRawBytes (Hash KesKey) where
serialiseToRawBytes (KesKeyHash vkh) =
Crypto.hashToBytes vkh

deserialiseFromRawBytes (AsHash AsKesKey) bs =
KesKeyHash <$> Crypto.hashFromBytes bs
eitherDeserialiseFromRawBytes (AsHash AsKesKey) bs =
maybeToRight (SerialiseAsRawBytesError "Unable to deserialise Hash KesKey") $
KesKeyHash <$> Crypto.hashFromBytes bs

instance HasTextEnvelope (VerificationKey KesKey) where
textEnvelopeType _ = "KesVerificationKey_"
Expand Down Expand Up @@ -192,15 +194,17 @@ instance SerialiseAsRawBytes (VerificationKey VrfKey) where
serialiseToRawBytes (VrfVerificationKey vk) =
Crypto.rawSerialiseVerKeyVRF vk

deserialiseFromRawBytes (AsVerificationKey AsVrfKey) bs =
VrfVerificationKey <$> Crypto.rawDeserialiseVerKeyVRF bs
eitherDeserialiseFromRawBytes (AsVerificationKey AsVrfKey) bs =
maybeToRight (SerialiseAsRawBytesError "Unable to deserialise VerificationKey VrfKey") $
VrfVerificationKey <$> Crypto.rawDeserialiseVerKeyVRF bs

instance SerialiseAsRawBytes (SigningKey VrfKey) where
serialiseToRawBytes (VrfSigningKey sk) =
Crypto.rawSerialiseSignKeyVRF sk

deserialiseFromRawBytes (AsSigningKey AsVrfKey) bs =
VrfSigningKey <$> Crypto.rawDeserialiseSignKeyVRF bs
eitherDeserialiseFromRawBytes (AsSigningKey AsVrfKey) bs =
maybeToRight (SerialiseAsRawBytesError "Unable to deserialise SigningKey VrfKey") $
VrfSigningKey <$> Crypto.rawDeserialiseSignKeyVRF bs

instance SerialiseAsBech32 (VerificationKey VrfKey) where
bech32PrefixFor _ = "vrf_vk"
Expand All @@ -222,8 +226,9 @@ instance SerialiseAsRawBytes (Hash VrfKey) where
serialiseToRawBytes (VrfKeyHash vkh) =
Crypto.hashToBytes vkh

deserialiseFromRawBytes (AsHash AsVrfKey) bs =
VrfKeyHash <$> Crypto.hashFromBytes bs
eitherDeserialiseFromRawBytes (AsHash AsVrfKey) bs =
maybeToRight (SerialiseAsRawBytesError "Unable to deserialise Hash VrfKey") $
VrfKeyHash <$> Crypto.hashFromBytes bs

instance HasTextEnvelope (VerificationKey VrfKey) where
textEnvelopeType _ = "VrfVerificationKey_" <> fromString (Crypto.algorithmNameVRF proxy)
Expand Down
Loading

0 comments on commit 9b9df9b

Please sign in to comment.