Skip to content

Commit 39631d0

Browse files
committed
Use MonadThrow in partial functions
1 parent 07b7146 commit 39631d0

File tree

7 files changed

+54
-39
lines changed

7 files changed

+54
-39
lines changed

cardano-wasm/cardano-wasm.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ executable cardano-wasm
5555
cardano-strict-containers,
5656
cborg,
5757
containers,
58+
exceptions,
5859
microlens,
5960
text,
6061

cardano-wasm/src/Cardano/Wasm/Api/Tx.hs

Whitespace-only changes.

cardano-wasm/src/Cardano/Wasm/General/ExceptionHandling.hs

Whitespace-only changes.

cardano-wasm/src/Cardano/Wasm/Internal/Api/Tx.hs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import Cardano.Ledger.Binary (Annotator, DecCBOR (decCBOR), EncCBOR, Version, de
2222
import Cardano.Wasm.Internal.ExceptionHandling (justOrError, rightOrError)
2323

2424
import Codec.CBOR.Write qualified as CBOR
25+
import Control.Monad.Catch (Exception (displayException), MonadThrow)
2526
import Data.Aeson (ToJSON (toJSON), (.=))
2627
import Data.Aeson qualified as Aeson
2728
import Data.Aeson.Types qualified as Aeson
@@ -64,15 +65,17 @@ instance FromJSON UnsignedTxObject where
6465
parseJSON :: HasCallStack => Aeson.Value -> Aeson.Parser UnsignedTxObject
6566
parseJSON = Aeson.withObject "UnsignedTxObject" $ \o -> do
6667
Exp.Some era <- o Aeson..: "era"
67-
let decode :: forall a. DecCBOR (Annotator a) => Text.Text -> Text.Text -> a
68+
let decode :: forall m a. (MonadThrow m, DecCBOR (Annotator a)) => Text.Text -> Text.Text -> m a
6869
decode desc cbor = do
69-
let cddlBS = rightOrError $ Base16.decode $ Text.encodeUtf8 cbor
70+
cddlBS <- rightOrError $ Base16.decode $ Text.encodeUtf8 cbor
7071
rightOrError $ decodeFullAnnotator (eraToVersion era) desc decCBOR (fromStrict cddlBS)
7172
keyWitnesses :: [Text.Text] <- o Aeson..: "keyWitnesess"
7273
tx :: Text.Text <- o Aeson..: "tx"
73-
obtainCommonConstraints era $
74+
obtainCommonConstraints era $ do
75+
decodedWitnesses <- mapM (toMonadFail . decode "KeyWitness") keyWitnesses
76+
decodedTx <- toMonadFail $ decode "Tx" tx
7477
return $
75-
UnsignedTxObject era (map (decode "KeyWitness") keyWitnesses) (Exp.UnsignedTx (decode "Tx" tx))
78+
UnsignedTxObject era decodedWitnesses (Exp.UnsignedTx decodedTx)
7679

7780
-- | Create a new unsigned transaction object for making a Conway era transaction.
7881
newConwayTxImpl :: UnsignedTxObject
@@ -88,11 +91,12 @@ addTxInputImpl (UnsignedTxObject era keyWitnesess (Exp.UnsignedTx tx)) txId txIx
8891

8992
-- | Add a simple transaction output to an unsigned transaction object.
9093
-- It takes a destination address and an amount in lovelace.
91-
addSimpleTxOutImpl :: HasCallStack => UnsignedTxObject -> String -> Ledger.Coin -> UnsignedTxObject
94+
addSimpleTxOutImpl
95+
:: (HasCallStack, MonadThrow m) => UnsignedTxObject -> String -> Ledger.Coin -> m UnsignedTxObject
9296
addSimpleTxOutImpl (UnsignedTxObject era keyWitnesess (Exp.UnsignedTx tx)) destAddr lovelaceAmount =
93-
obtainCommonConstraints era $
94-
let destAddress = deserialiseAddress era destAddr
95-
sbe = Api.convert era
97+
obtainCommonConstraints era $ do
98+
destAddress <- deserialiseAddress era destAddr
99+
let sbe = Api.convert era
96100
txOut =
97101
Api.TxOut
98102
destAddress
@@ -101,12 +105,11 @@ addSimpleTxOutImpl (UnsignedTxObject era keyWitnesess (Exp.UnsignedTx tx)) destA
101105
Shelley.ReferenceScriptNone
102106
shelleyTxOut = TxBody.toShelleyTxOutAny sbe txOut
103107
tx' = tx & Ledger.bodyTxL . Ledger.outputsTxBodyL %~ (<> StrictSeq.fromList [shelleyTxOut])
104-
in UnsignedTxObject era keyWitnesess $ Exp.UnsignedTx tx'
108+
return $ UnsignedTxObject era keyWitnesess $ Exp.UnsignedTx tx'
105109
where
106110
deserialiseAddress
107-
:: HasCallStack
108-
=> Exp.EraCommonConstraints era
109-
=> Exp.Era era -> String -> Api.AddressInEra era
111+
:: (HasCallStack, MonadThrow m, Exp.EraCommonConstraints era)
112+
=> Exp.Era era -> String -> m (Api.AddressInEra era)
110113
deserialiseAddress _eon destAddrStr =
111114
justOrError
112115
"Couldn't deserialise destination address"
@@ -155,14 +158,21 @@ instance FromJSON SignedTxObject where
155158
parseJSON :: HasCallStack => Aeson.Value -> Aeson.Parser SignedTxObject
156159
parseJSON = Aeson.withObject "SignedTxObject" $ \o -> do
157160
Exp.Some era <- o Aeson..: "era"
158-
let decode :: forall a. DecCBOR (Annotator a) => Text.Text -> Text.Text -> a
161+
let decode :: forall m a. (MonadThrow m, DecCBOR (Annotator a)) => Text.Text -> Text.Text -> m a
159162
decode desc cbor = do
160-
let cddlBS = rightOrError $ Base16.decode $ Text.encodeUtf8 cbor
163+
cddlBS <- rightOrError $ Base16.decode $ Text.encodeUtf8 cbor
161164
rightOrError $ decodeFullAnnotator (eraToVersion era) desc decCBOR (fromStrict cddlBS)
162165
tx :: Text.Text <- o Aeson..: "tx"
163-
obtainCommonConstraints era $
166+
obtainCommonConstraints era $ do
167+
decodedTx <- toMonadFail $ decode "Tx" tx
164168
return $
165-
SignedTxObject era (decode "Tx" tx)
169+
SignedTxObject era decodedTx
170+
171+
-- | Convert an 'Either' value to a 'MonadFail' monad. This can be useful for converting
172+
-- MonadThrow monads into Aeson Parser monads, but it loses the stack trace information.
173+
toMonadFail :: (Exception e, MonadFail m) => Either e a -> m a
174+
toMonadFail (Left e) = fail $ displayException e
175+
toMonadFail (Right a) = return a
166176

167177
-- | Convert a signed transaction object to a base16 encoded string of its CBOR representation.
168178
toCborImpl :: SignedTxObject -> String
Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
module Cardano.Wasm.Internal.ExceptionHandling where
22

3-
import Control.Exception (Exception, throwIO)
3+
import Control.Exception (Exception)
4+
import Control.Monad.Catch (MonadThrow (..))
45
import GHC.Stack (HasCallStack, withFrozenCallStack)
56

7+
newtype ExpectedJustException = ExpectedJustException String
8+
deriving Show
9+
10+
instance Exception ExpectedJustException
11+
612
newtype ExpectedRightException = ExpectedRightException String
713
deriving Show
814

915
instance Exception ExpectedRightException
1016

11-
justOrError :: HasCallStack => String -> Maybe a -> a
12-
justOrError e Nothing = withFrozenCallStack $ error e
13-
justOrError _ (Just a) = a
14-
15-
rightOrError :: (HasCallStack, Show e) => Either e a -> a
16-
rightOrError (Left e) = withFrozenCallStack $ error $ show e
17-
rightOrError (Right a) = a
17+
justOrError :: (HasCallStack, MonadThrow m) => String -> Maybe a -> m a
18+
justOrError e Nothing = withFrozenCallStack $ throwM $ ExpectedJustException e
19+
justOrError _ (Just a) = return a
1820

19-
rightOrErrorM :: (HasCallStack, Show e) => Either e a -> IO a
20-
rightOrErrorM (Left e) = withFrozenCallStack $ throwIO $ ExpectedRightException (show e)
21-
rightOrErrorM (Right a) = return a
21+
rightOrError :: (HasCallStack, MonadThrow m, Show e) => Either e a -> m a
22+
rightOrError (Left e) = withFrozenCallStack $ throwM $ ExpectedRightException $ show e
23+
rightOrError (Right a) = return a

cardano-wasm/src/Cardano/Wasm/Internal/JavaScript/Bridge.hs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ import Cardano.Api.Ledger qualified as Ledger
1818

1919
import Cardano.Wasm.Internal.Api.Info (apiInfo)
2020
import Cardano.Wasm.Internal.Api.Tx qualified as Wasm
21-
import Cardano.Wasm.Internal.ExceptionHandling (rightOrErrorM)
21+
import Cardano.Wasm.Internal.ExceptionHandling (rightOrError)
2222

2323
import Control.Exception (evaluate)
24+
import Control.Monad (join)
2425
import Data.Aeson qualified as Aeson
2526
import Data.ByteString.UTF8 (fromString, toString)
2627
import Data.Text (Text)
@@ -136,12 +137,12 @@ instance (Api.FromJSON a, Typeable a) => FromJSVal JSVal a where
136137
instance FromJSVal JSSigningKey (Api.SigningKey Api.PaymentKey) where
137138
fromJSVal :: HasCallStack => JSSigningKey -> IO (Api.SigningKey Api.PaymentKey)
138139
fromJSVal jsString = do
139-
rightOrErrorM $ Api.deserialiseFromBech32 (Text.pack (fromJSString jsString))
140+
rightOrError $ Api.deserialiseFromBech32 (Text.pack (fromJSString jsString))
140141

141142
instance FromJSVal JSTxId Api.TxId where
142143
fromJSVal :: HasCallStack => JSTxId -> IO Api.TxId
143144
fromJSVal jsString = do
144-
rightOrErrorM $ Api.deserialiseFromRawBytesHex (fromString (fromJSString jsString))
145+
rightOrError $ Api.deserialiseFromRawBytesHex (fromString (fromJSString jsString))
145146

146147
instance FromJSVal JSTxIx Api.TxIx where
147148
fromJSVal = return . Api.TxIx . fromIntegral
@@ -181,13 +182,14 @@ addTxInput jsUnsignedTx jsTxId jsTxIx =
181182

182183
-- | Add a simple transaction output (address and lovelace amount) to an unsigned transaction.
183184
addSimpleTxOut :: JSUnsignedTx -> JSString -> JSCoin -> IO JSUnsignedTx
184-
addSimpleTxOut jsUnsignedTx jsDestAddr jsCoin = do
185+
addSimpleTxOut jsUnsignedTx jsDestAddr jsCoin =
185186
toJSVal
186-
=<< ( Wasm.addSimpleTxOutImpl
187-
<$> fromJSVal jsUnsignedTx
188-
<*> fromJSVal jsDestAddr
189-
<*> fromJSVal jsCoin
190-
)
187+
=<< join
188+
( Wasm.addSimpleTxOutImpl
189+
<$> fromJSVal jsUnsignedTx
190+
<*> fromJSVal jsDestAddr
191+
<*> fromJSVal jsCoin
192+
)
191193

192194
-- | Set the transaction fee for an unsigned transaction.
193195
setFee :: JSUnsignedTx -> JSCoin -> IO JSUnsignedTx
@@ -210,7 +212,7 @@ addSigningKey jsUnsignedTx jsSigningKey =
210212
-- | Sign an unsigned transaction.
211213
signTx :: JSUnsignedTx -> IO JSSignedTx
212214
signTx jsUnsignedTx =
213-
toJSVal =<< Wasm.signTxImpl <$> fromJSVal jsUnsignedTx
215+
toJSVal . Wasm.signTxImpl =<< fromJSVal jsUnsignedTx
214216

215217
-- * SignedTxObject
216218

@@ -220,7 +222,7 @@ foreign export javascript "txToCbor"
220222
-- | Convert a signed transaction to its CBOR representation (hex-encoded string).
221223
txToCbor :: JSSignedTx -> IO JSString
222224
txToCbor jsSignedTx =
223-
toJSVal =<< Wasm.toCborImpl <$> fromJSVal jsSignedTx
225+
toJSVal . Wasm.toCborImpl =<< fromJSVal jsSignedTx
224226

225227
-- * API Information
226228

@@ -230,4 +232,4 @@ foreign export javascript "getApiInfo"
230232
getApiInfo :: IO JSApiInfo
231233
getApiInfo = toJSVal apiInfo
232234

233-
#endif
235+
#endif

cardano-wasm/src/Cardano/Wasm/JavaScript/Bridge.hs

Whitespace-only changes.

0 commit comments

Comments
 (0)