11{-# LANGUAGE FlexibleInstances #-}
2+ {-# LANGUAGE GADTs #-}
3+ {-# LANGUAGE LambdaCase #-}
24{-# LANGUAGE MultiParamTypeClasses #-}
35{-# LANGUAGE OverloadedLabels #-}
6+ {-# LANGUAGE ScopedTypeVariables #-}
7+ {-# LANGUAGE TypeApplications #-}
48{-# OPTIONS_GHC -Wno-orphans #-}
59
610module Cardano.Rpc.Server.Internal.Orphans () where
711
8- import Cardano.Api.Block (ChainPoint (.. ), Hash (.. ), SlotNo (.. ))
9- import Cardano.Api.Era (Inject (.. ))
12+ import Cardano.Api.Address
13+ import Cardano.Api.Block
14+ import Cardano.Api.Era
15+ import Cardano.Api.Error
16+ import Cardano.Api.Ledger qualified as L
17+ import Cardano.Api.Plutus
18+ import Cardano.Api.Pretty
19+ import Cardano.Api.Serialise.Raw
20+ import Cardano.Api.Tx
21+ import Cardano.Api.Value
1022import Cardano.Rpc.Proto.Api.UtxoRpc.Query qualified as UtxoRpc
1123
12- import Cardano.Ledger.Plutus qualified as L
24+ import RIO hiding ( toList )
1325
14- import RIO
15-
16- import Data.ByteString.Short qualified as SBS
1726import Data.ProtoLens (defMessage )
1827import Data.Ratio (Ratio , denominator , numerator , (%) )
28+ import Data.Text.Encoding qualified as T
29+ import GHC.IsList
1930import Network.GRPC.Spec
2031
32+ ---------------
33+ -- Conversion
34+ ---------------
35+
36+ -- It's easier to use 'Proto a' wrappers for RPC types, because it makes lens automatically available.
37+
38+ -- TODO: write property tests for roundtripping injections
39+
2140instance Inject (Proto UtxoRpc. RationalNumber ) (Ratio Integer ) where
2241 inject r = r ^. # numerator . to fromIntegral % r ^. # denominator . to fromIntegral
2342
@@ -40,12 +59,116 @@ instance Inject L.ExUnits (Proto UtxoRpc.ExUnits) where
4059 & # memory .~ fromIntegral mem
4160 & # steps .~ fromIntegral steps
4261
43- instance Inject ChainPoint (Proto UtxoRpc. ChainPoint ) where
44- inject chainPoint = do
45- let (slotNo, blockHash) =
46- case chainPoint of
47- ChainPointAtGenesis -> (0 , mempty )
48- ChainPoint (SlotNo slot) (HeaderHash hash) -> (slot, SBS. fromShort hash)
62+ -- | Note that conversion is not total in the other direction
63+ instance Inject TxIn (Proto UtxoRpc. TxoRef ) where
64+ inject (TxIn txId' (TxIx txIx)) =
4965 defMessage
50- & # slot .~ slotNo
51- & # hash .~ blockHash
66+ & # hash .~ serialiseToRawBytes txId'
67+ & # index .~ fromIntegral txIx
68+
69+ instance Inject ScriptData (Proto UtxoRpc. PlutusData ) where
70+ inject = \ case
71+ ScriptDataBytes bs ->
72+ defMessage & # boundedBytes .~ bs
73+ ScriptDataNumber int ->
74+ defMessage & # bigInt . # int .~ fromIntegral int
75+ ScriptDataList sds ->
76+ defMessage & # array . # items .~ map inject sds
77+ ScriptDataMap elements -> do
78+ let pairs =
79+ elements <&> \ (k, v) ->
80+ defMessage
81+ & # key .~ inject k
82+ & # value .~ inject v
83+ defMessage & # map . # pairs .~ pairs
84+ ScriptDataConstructor tag args -> do
85+ let constr =
86+ defMessage
87+ & # tag .~ fromIntegral tag
88+ & # fields .~ map inject args
89+ defMessage & # constr .~ constr
90+
91+ instance Inject (ReferenceScript era ) (Proto UtxoRpc. Script ) where
92+ inject ReferenceScriptNone = defMessage
93+ inject (ReferenceScript _ (ScriptInAnyLang _ script)) =
94+ case script of
95+ SimpleScript ss ->
96+ defMessage & # native .~ inject ss
97+ PlutusScript PlutusScriptV1 ps ->
98+ defMessage & # plutusV1 .~ serialiseToRawBytes ps
99+ PlutusScript PlutusScriptV2 ps ->
100+ defMessage & # plutusV2 .~ serialiseToRawBytes ps
101+ PlutusScript PlutusScriptV3 ps ->
102+ defMessage & # plutusV3 .~ serialiseToRawBytes ps
103+
104+ instance Inject SimpleScript (Proto UtxoRpc. NativeScript ) where
105+ inject = \ case
106+ RequireSignature paymentKeyHash ->
107+ defMessage & # scriptPubkey .~ serialiseToRawBytes paymentKeyHash
108+ RequireTimeBefore (SlotNo slotNo) ->
109+ defMessage & # invalidHereafter .~ slotNo
110+ RequireTimeAfter (SlotNo slotNo) ->
111+ defMessage & # invalidBefore .~ slotNo
112+ RequireAllOf scripts ->
113+ defMessage & # scriptAll . # items .~ map inject scripts
114+ RequireAnyOf scripts ->
115+ defMessage & # scriptAny . # items .~ map inject scripts
116+ RequireMOf k scripts -> do
117+ let nScriptsOf =
118+ defMessage
119+ & # k .~ fromIntegral k
120+ & # scripts .~ map inject scripts
121+ defMessage & # scriptNOfK .~ nScriptsOf
122+
123+ instance IsCardanoEra era => Inject (UTxO era ) [Proto UtxoRpc. AnyUtxoData ] where
124+ inject utxo =
125+ toList utxo <&> \ (txIn, TxOut addressInEra txOutValue datum script) -> do
126+ let multiAsset =
127+ fromList $
128+ toList (valueToPolicyAssets $ txOutValueToValue txOutValue) <&> \ (pId, policyAssets) -> do
129+ let assets =
130+ toList policyAssets <&> \ (assetName, Quantity qty) -> do
131+ defMessage
132+ & # name .~ serialiseToRawBytes assetName
133+ & # outputCoin .~ fromIntegral qty
134+ & # mintCoin .~ 0 -- TODO what is this supposed to mean?
135+ defMessage
136+ & # policyId .~ serialiseToRawBytes pId
137+ & # assets .~ assets
138+ & # redeemer .~ defMessage -- TODO remove this field from proto
139+ datumRpc = case datum of
140+ TxOutDatumNone ->
141+ defMessage
142+ TxOutDatumHash _ scriptDataHash ->
143+ defMessage
144+ & # hash .~ serialiseToRawBytes scriptDataHash
145+ & # maybe'payload .~ Nothing -- we don't have it
146+ & # originalCbor .~ mempty -- we don't have it
147+ TxOutDatumInline _ hashableScriptData ->
148+ defMessage
149+ & # hash .~ serialiseToRawBytes (hashScriptDataBytes hashableScriptData)
150+ & # payload .~ inject (getScriptData hashableScriptData)
151+ & # originalCbor .~ getOriginalScriptDataBytes hashableScriptData
152+
153+ protoTxOut =
154+ defMessage
155+ -- TODO we don't have serialiseToRawBytes for AddressInEra, so perhaps this is wrong, because 'address'
156+ -- has type bytes, but we're putting text there
157+ & # address .~ T. encodeUtf8 (cardanoEraConstraints (cardanoEra @ era ) $ serialiseAddress addressInEra)
158+ & # coin .~ fromIntegral (L. unCoin (txOutValueToLovelace txOutValue))
159+ & # assets .~ multiAsset
160+ & # datum .~ datumRpc
161+ & # script .~ inject script
162+ defMessage
163+ & # nativeBytes .~ " " -- TODO where to get that from? run cbor serialisation of utxos list?
164+ & # txoRef .~ inject txIn
165+ & # cardano .~ protoTxOut
166+
167+ -----------
168+ -- Errors
169+ -----------
170+
171+ -- TODO add RIO to cardano-api and move this instance there
172+
173+ instance Error StringException where
174+ prettyError = pshow
0 commit comments