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.UTxO (UTxO )
22+ import Cardano.Api.Value
1023import Cardano.Rpc.Proto.Api.UtxoRpc.Query qualified as UtxoRpc
1124
1225import Cardano.Ledger.Plutus qualified as L
1326
14- import RIO
27+ import RIO hiding ( toList )
1528
16- import Data.ByteString.Short qualified as SBS
1729import Data.ProtoLens (defMessage )
1830import Data.Ratio (Ratio , denominator , numerator , (%) )
31+ import Data.Text.Encoding qualified as T
32+ import GHC.IsList
1933import Network.GRPC.Spec
2034
35+ ---------------
36+ -- Conversion
37+ ---------------
38+
39+ -- It's easier to use 'Proto a' wrappers for RPC types, because it makes lens automatically available.
40+
41+ -- TODO: write property tests for roundtripping injections
42+
2143instance Inject (Proto UtxoRpc. RationalNumber ) (Ratio Integer ) where
2244 inject r = r ^. # numerator . to fromIntegral % r ^. # denominator . to fromIntegral
2345
@@ -40,12 +62,116 @@ instance Inject L.ExUnits (Proto UtxoRpc.ExUnits) where
4062 & # memory .~ fromIntegral mem
4163 & # steps .~ fromIntegral steps
4264
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)
65+ -- | Note that conversion is not total in the other direction
66+ instance Inject TxIn (Proto UtxoRpc. TxoRef ) where
67+ inject (TxIn txId' (TxIx txIx)) =
4968 defMessage
50- & # slot .~ slotNo
51- & # hash .~ blockHash
69+ & # hash .~ serialiseToRawBytes txId'
70+ & # index .~ fromIntegral txIx
71+
72+ instance Inject ScriptData (Proto UtxoRpc. PlutusData ) where
73+ inject = \ case
74+ ScriptDataBytes bs ->
75+ defMessage & # boundedBytes .~ bs
76+ ScriptDataNumber int ->
77+ defMessage & # bigInt . # int .~ fromIntegral int
78+ ScriptDataList sds ->
79+ defMessage & # array . # items .~ map inject sds
80+ ScriptDataMap elements -> do
81+ let pairs =
82+ elements <&> \ (k, v) ->
83+ defMessage
84+ & # key .~ inject k
85+ & # value .~ inject v
86+ defMessage & # map . # pairs .~ pairs
87+ ScriptDataConstructor tag args -> do
88+ let constr =
89+ defMessage
90+ & # tag .~ fromIntegral tag
91+ & # fields .~ map inject args
92+ defMessage & # constr .~ constr
93+
94+ instance Inject (ReferenceScript era ) (Proto UtxoRpc. Script ) where
95+ inject ReferenceScriptNone = defMessage
96+ inject (ReferenceScript _ (ScriptInAnyLang _ script)) =
97+ case script of
98+ SimpleScript ss ->
99+ defMessage & # native .~ inject ss
100+ PlutusScript PlutusScriptV1 ps ->
101+ defMessage & # plutusV1 .~ serialiseToRawBytes ps
102+ PlutusScript PlutusScriptV2 ps ->
103+ defMessage & # plutusV2 .~ serialiseToRawBytes ps
104+ PlutusScript PlutusScriptV3 ps ->
105+ defMessage & # plutusV3 .~ serialiseToRawBytes ps
106+
107+ instance Inject SimpleScript (Proto UtxoRpc. NativeScript ) where
108+ inject = \ case
109+ RequireSignature paymentKeyHash ->
110+ defMessage & # scriptPubkey .~ serialiseToRawBytes paymentKeyHash
111+ RequireTimeBefore (SlotNo slotNo) ->
112+ defMessage & # invalidHereafter .~ slotNo
113+ RequireTimeAfter (SlotNo slotNo) ->
114+ defMessage & # invalidBefore .~ slotNo
115+ RequireAllOf scripts ->
116+ defMessage & # scriptAll . # items .~ map inject scripts
117+ RequireAnyOf scripts ->
118+ defMessage & # scriptAny . # items .~ map inject scripts
119+ RequireMOf k scripts -> do
120+ let nScriptsOf =
121+ defMessage
122+ & # k .~ fromIntegral k
123+ & # scripts .~ map inject scripts
124+ defMessage & # scriptNOfK .~ nScriptsOf
125+
126+ instance IsCardanoEra era => Inject (UTxO era ) [Proto UtxoRpc. AnyUtxoData ] where
127+ inject utxo =
128+ toList utxo <&> \ (txIn, TxOut addressInEra txOutValue datum script) -> do
129+ let multiAsset =
130+ fromList $
131+ toList (valueToPolicyAssets $ txOutValueToValue txOutValue) <&> \ (pId, policyAssets) -> do
132+ let assets =
133+ toList policyAssets <&> \ (assetName, Quantity qty) -> do
134+ defMessage
135+ & # name .~ serialiseToRawBytes assetName
136+ & # outputCoin .~ fromIntegral qty
137+ & # mintCoin .~ 0 -- TODO what is this supposed to mean?
138+ defMessage
139+ & # policyId .~ serialiseToRawBytes pId
140+ & # assets .~ assets
141+ & # redeemer .~ defMessage -- TODO remove this field from proto
142+ datumRpc = case datum of
143+ TxOutDatumNone ->
144+ defMessage
145+ TxOutDatumHash _ scriptDataHash ->
146+ defMessage
147+ & # hash .~ serialiseToRawBytes scriptDataHash
148+ & # maybe'payload .~ Nothing -- we don't have it
149+ & # originalCbor .~ mempty -- we don't have it
150+ TxOutDatumInline _ hashableScriptData ->
151+ defMessage
152+ & # hash .~ serialiseToRawBytes (hashScriptDataBytes hashableScriptData)
153+ & # payload .~ inject (getScriptData hashableScriptData)
154+ & # originalCbor .~ getOriginalScriptDataBytes hashableScriptData
155+
156+ protoTxOut =
157+ defMessage
158+ -- TODO we don't have serialiseToRawBytes for AddressInEra, so perhaps this is wrong, because 'address'
159+ -- has type bytes, but we're putting text there
160+ & # address .~ T. encodeUtf8 (cardanoEraConstraints (cardanoEra @ era ) $ serialiseAddress addressInEra)
161+ & # coin .~ fromIntegral (L. unCoin (txOutValueToLovelace txOutValue))
162+ & # assets .~ multiAsset
163+ & # datum .~ datumRpc
164+ & # script .~ inject script
165+ defMessage
166+ & # nativeBytes .~ " " -- TODO where to get that from? run cbor serialisation of utxos list?
167+ & # txoRef .~ inject txIn
168+ & # cardano .~ protoTxOut
169+
170+ -----------
171+ -- Errors
172+ -----------
173+
174+ -- TODO add RIO to cardano-api and move this instance there
175+
176+ instance Error StringException where
177+ prettyError = pshow
0 commit comments