Skip to content

Commit 52b3c77

Browse files
committed
Add ToJSON/FromJSON instances for EraTxWits
* Add ToJSON, FromJSON and NFData as EraTxWits superclass constraints * Add ToJSON/FromJSON for WitVKey, BootstrapWitness * Add ToJSONKey/FromJSONKey for AccountId * Add ToJSON/FromJSON for Inclusive and Exclusive * Add FromJSON for TxIn; fix txInToText to use unTxIx * Add FromJSON for PoolCert * Add ToJSON/FromJSON for ShelleyTxWits era * Add FromJSON for AsIx, AlonzoPlutusPurpose AsIx, TxDats, Redeemers, AlonzoTxWits * Add FromJSON for ConwayDelegCert, ConwayGovCert, ConwayTxCert era, ConwayPlutusPurpose * Add FromJSON for GovActionId, Voter, Vote, VotingProcedure, ProposalProcedure, GovAction, GovPurposeId * Add ToJSON/FromJSON for AccountBalanceInterval, DijkstraScript * Add FromJSON for DijkstraDelegCert, DijkstraTxCert era * Add round-trip JSON property test for TxWits era
1 parent e45b5a9 commit 52b3c77

20 files changed

Lines changed: 468 additions & 37 deletions

File tree

eras/alonzo/impl/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
## 1.16.0.0
44

55
* Add `ToJSON` and `FromJSON` instances for `AlonzoTxAuxData era`
6+
* Add `FromJSON` instance for `AsIx ix it`
7+
* Add `FromJSON` instance for `AlonzoPlutusPurpose AsIx era`
8+
* Add `ToJSON` and `FromJSON` instances for `TxDats era`, `Redeemers era`, and `AlonzoTxWits era`
69
* Replace `scriptsProvided` and `scriptsNeeded` in `mkScriptIntegrity` signature with `Set Language`
710
* Add `plutusLanguagesUsedStAnnTx` to `AlonzoEraUTxO` and a helper to implement it `plutusLanguagesUsedAlonzoStAnnTx`
811
* Add `plutusScriptsWithContextStAnnTx` to `AlonzoEraUTxO` and a helper to implement it `plutusScriptsWithContextAlonzoStAnnTx`

eras/alonzo/impl/src/Cardano/Ledger/Alonzo/TxWits.hs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,10 @@ import Cardano.Ledger.Shelley.TxWits (
122122
import Control.DeepSeq (NFData)
123123
import Control.Monad (when, (>=>))
124124
import Control.Monad.Trans.Fail (runFail)
125+
import Data.Aeson (FromJSON (..), ToJSON (..), object, withArray, withObject, (.:), (.=))
126+
import qualified Data.Aeson as Aeson
125127
import Data.Coerce (coerce)
128+
import qualified Data.Foldable as Foldable
126129
import qualified Data.List.NonEmpty as NE
127130
import Data.Map.Strict (Map)
128131
import qualified Data.Map.Strict as Map
@@ -746,3 +749,80 @@ encodeWithSetTag xs =
746749
(natVersion @9)
747750
(encodeTag setTag <> encCBOR xs)
748751
(encCBOR xs)
752+
753+
instance (Era era, ToJSON (Data era)) => ToJSON (TxDats era) where
754+
toJSON (TxDats m) =
755+
Aeson.toJSON
756+
[ object ["dataHash" .= k, "data" .= v]
757+
| (k, v) <- Map.toList m
758+
]
759+
760+
instance (Era era, FromJSON (Data era)) => FromJSON (TxDats era) where
761+
parseJSON = withArray "TxDats" $ \arr -> do
762+
pairs <- mapM parsePair (Foldable.toList arr)
763+
pure $ TxDats (Map.fromList pairs)
764+
where
765+
parsePair = withObject "TxDat" $ \o ->
766+
(,) <$> o .: "dataHash" <*> o .: "data"
767+
768+
instance
769+
( AlonzoEraScript era
770+
, ToJSON (Data era)
771+
, ToJSON (PlutusPurpose AsIx era)
772+
) =>
773+
ToJSON (Redeemers era)
774+
where
775+
toJSON (Redeemers rdmrs) =
776+
Aeson.toJSON
777+
[ object ["purpose" .= k, "data" .= d, "exUnits" .= ex]
778+
| (k, (d, ex)) <- Map.toList rdmrs
779+
]
780+
781+
instance
782+
( AlonzoEraScript era
783+
, FromJSON (Data era)
784+
, FromJSON (PlutusPurpose AsIx era)
785+
) =>
786+
FromJSON (Redeemers era)
787+
where
788+
parseJSON = withArray "Redeemers" $ \arr -> do
789+
pairs <- mapM parseRedeemer (Foldable.toList arr)
790+
pure $ Redeemers (Map.fromList pairs)
791+
where
792+
parseRedeemer = withObject "Redeemer" $ \o ->
793+
(,)
794+
<$> o .: "purpose"
795+
<*> ((,) <$> o .: "data" <*> o .: "exUnits")
796+
797+
instance
798+
( AlonzoEraScript era
799+
, ToJSON (Script era)
800+
, ToJSON (Data era)
801+
, ToJSON (PlutusPurpose AsIx era)
802+
) =>
803+
ToJSON (AlonzoTxWits era)
804+
where
805+
toJSON (AlonzoTxWits vkeys boots scripts dats rdmrs) =
806+
object
807+
[ "addrWits" .= Set.toList vkeys
808+
, "bootWits" .= Set.toList boots
809+
, "scriptWits" .= scripts
810+
, "datums" .= dats
811+
, "redeemers" .= rdmrs
812+
]
813+
814+
instance
815+
( AlonzoEraScript era
816+
, FromJSON (Script era)
817+
, FromJSON (Data era)
818+
, FromJSON (PlutusPurpose AsIx era)
819+
) =>
820+
FromJSON (AlonzoTxWits era)
821+
where
822+
parseJSON = withObject "AlonzoTxWits" $ \o ->
823+
AlonzoTxWits
824+
<$> (Set.fromList <$> o .: "addrWits")
825+
<*> (Set.fromList <$> o .: "bootWits")
826+
<*> o .: "scriptWits"
827+
<*> o .: "datums"
828+
<*> o .: "redeemers"

eras/conway/impl/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## 1.23.0.0
44

5+
* Add `FromJSON` instances for `GovActionId`, `Voter`, `Vote`, `VotingProcedure`, `ProposalProcedure`, `GovAction`, and `GovPurposeId`
6+
* Add `FromJSON` instances for `ConwayDelegCert`, `ConwayGovCert`, and `ConwayTxCert era`
7+
* Add `FromJSON` instance for `ConwayPlutusPurpose f era`
58
* Add `ToJSON` instance for `DefaultVote`.
69
* Add `injectStakeCredentials`, `injectDRepsThenDelegs` to `Cardano.Ledger.Conway.Transition`
710
* Add `ConwayExtraConfig` type and `cgExtraConfig` field to `ConwayGenesis`

eras/conway/impl/src/Cardano/Ledger/Conway/Governance/Procedures.hs

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22
{-# LANGUAGE BangPatterns #-}
33
{-# LANGUAGE DataKinds #-}
44
{-# LANGUAGE DeriveGeneric #-}
5-
{-# LANGUAGE DerivingStrategies #-}
65
{-# LANGUAGE DerivingVia #-}
76
{-# LANGUAGE FlexibleContexts #-}
87
{-# LANGUAGE GADTs #-}
98
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
10-
{-# LANGUAGE KindSignatures #-}
119
{-# LANGUAGE LambdaCase #-}
1210
{-# LANGUAGE MultiParamTypeClasses #-}
1311
{-# LANGUAGE NamedFieldPuns #-}
@@ -21,7 +19,6 @@
2119
{-# LANGUAGE TupleSections #-}
2220
{-# LANGUAGE TypeApplications #-}
2321
{-# LANGUAGE TypeFamilies #-}
24-
{-# LANGUAGE TypeOperators #-}
2522
{-# LANGUAGE TypeSynonymInstances #-}
2623
{-# LANGUAGE UndecidableInstances #-}
2724

@@ -125,7 +122,7 @@ import Cardano.Ledger.Binary.Coders (
125122
(<!),
126123
)
127124
import Cardano.Ledger.Coin (Coin)
128-
import Cardano.Ledger.Credential (Credential (..), credToText)
125+
import Cardano.Ledger.Credential (Credential (..), credToText, parseCredential)
129126
import Cardano.Ledger.Shelley.RewardProvenance ()
130127
import Cardano.Ledger.TxIn (TxId (..))
131128
import Cardano.Slotting.Slot (EpochNo)
@@ -135,14 +132,16 @@ import Control.Monad.Trans (lift)
135132
import Control.Monad.Trans.State.Strict (get, put)
136133
import Data.Aeson (
137134
FromJSON (..),
135+
FromJSONKey (..),
138136
KeyValue (..),
139137
ToJSON (..),
140138
ToJSONKey (..),
141139
withObject,
142140
(.:),
143141
(.:?),
144142
)
145-
import Data.Aeson.Types (toJSONKeyText)
143+
import qualified Data.Aeson as Aeson
144+
import Data.Aeson.Types (FromJSONKeyFunction (..), toJSONKeyText)
146145
import Data.Data (Typeable)
147146
import Data.Default
148147
import Data.Kind
@@ -158,6 +157,7 @@ import Data.Word (Word16)
158157
import GHC.Generics (Generic)
159158
import Lens.Micro (Lens', lens, (^.))
160159
import NoThunks.Class (NoThunks)
160+
import Text.Read (readMaybe)
161161

162162
newtype GovActionIx = GovActionIx {unGovActionIx :: Word16}
163163
deriving
@@ -170,6 +170,7 @@ newtype GovActionIx = GovActionIx {unGovActionIx :: Word16}
170170
, EncCBOR
171171
, DecCBOR
172172
, ToJSON
173+
, FromJSON
173174
)
174175

175176
data GovActionId = GovActionId
@@ -216,6 +217,26 @@ govActionIdToText (GovActionId (TxId txidHash) (GovActionIx ix)) =
216217
<> Text.pack "#"
217218
<> Text.pack (show ix)
218219

220+
instance FromJSON GovActionId where
221+
parseJSON = withObject "GovActionId" $ \o ->
222+
GovActionId
223+
<$> o .: "txId"
224+
<*> o .: "govActionIx"
225+
226+
instance FromJSONKey GovActionId where
227+
fromJSONKey = FromJSONKeyTextParser parseGovActionId
228+
229+
parseGovActionId :: MonadFail m => Text.Text -> m GovActionId
230+
parseGovActionId t = case Text.splitOn "#" t of
231+
[txIdText, ixText] -> do
232+
txId <- case Aeson.fromJSON (Aeson.String txIdText) of
233+
Aeson.Success v -> pure v
234+
Aeson.Error e -> fail $ "GovActionId: invalid txId: " <> e
235+
ix <-
236+
maybe (fail "GovActionId: invalid index") (pure . GovActionIx) (readMaybe $ Text.unpack ixText)
237+
pure $ GovActionId txId ix
238+
_ -> fail "GovActionId: expected 'txhash#ix'"
239+
219240
data GovActionState era = GovActionState
220241
{ gasId :: !GovActionId
221242
, gasCommitteeVotes :: !(Map (Credential HotCommitteeRole) Vote)
@@ -273,7 +294,7 @@ deriving via
273294
EraPParams era => ToJSON (GovActionState era)
274295

275296
instance EraPParams era => ToKeyValuePairs (GovActionState era) where
276-
toKeyValuePairs gas@(GovActionState _ _ _ _ _ _ _) =
297+
toKeyValuePairs gas =
277298
let GovActionState {..} = gas
278299
in [ "actionId" .= gasId
279300
, "committeeVotes" .= gasCommitteeVotes
@@ -352,6 +373,22 @@ instance ToJSONKey Voter where
352373
StakePoolVoter kh ->
353374
"stakepool-" <> credToText (KeyHashObj kh)
354375

376+
instance FromJSON Voter
377+
378+
instance FromJSONKey Voter where
379+
fromJSONKey = FromJSONKeyTextParser parseVoter
380+
381+
parseVoter :: MonadFail m => Text.Text -> m Voter
382+
parseVoter t = case Text.splitOn "-" t of
383+
("committee" : rest) -> CommitteeVoter <$> parseCredential (Text.intercalate "-" rest)
384+
("drep" : rest) -> DRepVoter <$> parseCredential (Text.intercalate "-" rest)
385+
("stakepool" : rest) -> do
386+
cred <- parseCredential (Text.intercalate "-" rest)
387+
case cred of
388+
KeyHashObj kh -> pure $ StakePoolVoter kh
389+
ScriptHashObj _ -> fail "StakePool voter cannot be a script hash"
390+
_ -> fail $ "Invalid Voter: " <> show t
391+
355392
instance DecCBOR Voter where
356393
decCBOR = decodeRecordSum "Voter" $ \case
357394
0 -> (2,) . CommitteeVoter . KeyHashObj <$> decCBOR
@@ -387,6 +424,8 @@ data Vote
387424

388425
instance ToJSON Vote
389426

427+
instance FromJSON Vote
428+
390429
instance NoThunks Vote
391430

392431
instance NFData Vote
@@ -401,7 +440,7 @@ newtype VotingProcedures era = VotingProcedures
401440
{ unVotingProcedures :: Map Voter (Map GovActionId (VotingProcedure era))
402441
}
403442
deriving stock (Generic, Eq, Show)
404-
deriving newtype (NoThunks, EncCBOR, ToJSON)
443+
deriving newtype (NoThunks, EncCBOR, ToJSON, FromJSON)
405444

406445
deriving newtype instance Era era => NFData (VotingProcedures era)
407446

@@ -485,6 +524,12 @@ instance EraPParams era => ToKeyValuePairs (VotingProcedure era) where
485524
, "decision" .= vProcVote
486525
]
487526

527+
instance EraPParams era => FromJSON (VotingProcedure era) where
528+
parseJSON = withObject "VotingProcedure" $ \o ->
529+
VotingProcedure
530+
<$> o .: "decision"
531+
<*> o .: "anchor"
532+
488533
-- | Attaches indices to a sequence of proposal procedures. The indices grow
489534
-- from left to right.
490535
indexedGovProps ::
@@ -549,14 +594,22 @@ deriving via
549594
EraPParams era => ToJSON (ProposalProcedure era)
550595

551596
instance EraPParams era => ToKeyValuePairs (ProposalProcedure era) where
552-
toKeyValuePairs proposalProcedure@(ProposalProcedure _ _ _ _) =
597+
toKeyValuePairs proposalProcedure =
553598
let ProposalProcedure {..} = proposalProcedure
554599
in [ "deposit" .= pProcDeposit
555600
, "returnAddr" .= pProcReturnAddr
556601
, "govAction" .= pProcGovAction
557602
, "anchor" .= pProcAnchor
558603
]
559604

605+
instance EraPParams era => FromJSON (ProposalProcedure era) where
606+
parseJSON = withObject "ProposalProcedure" $ \o ->
607+
ProposalProcedure
608+
<$> o .: "deposit"
609+
<*> o .: "returnAddr"
610+
<*> o .: "govAction"
611+
<*> o .: "anchor"
612+
560613
data Committee era = Committee
561614
{ committeeMembers :: !(Map (Credential ColdCommitteeRole) EpochNo)
562615
-- ^ Committee members with epoch number when each of them expires
@@ -663,6 +716,10 @@ deriving newtype instance ToJSONKey (GovPurposeId (p :: GovActionPurpose))
663716

664717
deriving newtype instance ToJSON (GovPurposeId (p :: GovActionPurpose))
665718

719+
deriving newtype instance FromJSON (GovPurposeId (p :: GovActionPurpose))
720+
721+
deriving newtype instance FromJSONKey (GovPurposeId (p :: GovActionPurpose))
722+
666723
deriving newtype instance Show (GovPurposeId (p :: GovActionPurpose))
667724

668725
-- | Abstract data type for representing relationship of governance action with the same purpose
@@ -736,7 +793,7 @@ instance
736793
(forall p. Typeable p => EncCBOR (f (GovPurposeId (p :: GovActionPurpose)))) =>
737794
EncCBOR (GovRelation f)
738795
where
739-
encCBOR govPurpose@(GovRelation _ _ _ _) =
796+
encCBOR govPurpose =
740797
let GovRelation {..} = govPurpose
741798
in encodeListLen 4
742799
<> encCBOR grPParamUpdate
@@ -748,7 +805,7 @@ instance
748805
(forall p. ToJSON (f (GovPurposeId (p :: GovActionPurpose)))) =>
749806
ToKeyValuePairs (GovRelation f)
750807
where
751-
toKeyValuePairs govPurpose@(GovRelation _ _ _ _) =
808+
toKeyValuePairs govPurpose =
752809
let GovRelation {..} = govPurpose
753810
in [ "PParamUpdate" .= grPParamUpdate
754811
, "HardFork" .= grHardFork
@@ -868,6 +925,8 @@ instance EraPParams era => NFData (GovAction era)
868925

869926
instance EraPParams era => ToJSON (GovAction era)
870927

928+
instance EraPParams era => FromJSON (GovAction era)
929+
871930
instance EraPParams era => DecCBOR (GovAction era) where
872931
decCBOR =
873932
decode $ Summands "GovAction" $ \case

eras/conway/impl/src/Cardano/Ledger/Conway/Scripts.hs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ import Cardano.Ledger.Plutus.Language
5353
import Cardano.Ledger.Shelley.Scripts (ShelleyEraScript (..))
5454
import Cardano.Ledger.TxIn (TxIn)
5555
import Control.DeepSeq (NFData (..), rwhnf)
56-
import Data.Aeson (ToJSON (..), (.=))
56+
import Data.Aeson (FromJSON (..), ToJSON (..), withObject, (.:), (.=))
5757
import Data.MemPack
5858
import Data.Typeable
5959
import Data.Word (Word32)
@@ -312,6 +312,25 @@ instance
312312
where
313313
kindObjectWithValue name n = kindObjectValue name ["value" .= n]
314314

315+
instance
316+
( forall a b. (FromJSON a, FromJSON b) => FromJSON (f a b)
317+
, FromJSON (TxCert era)
318+
, EraPParams era
319+
) =>
320+
FromJSON (ConwayPlutusPurpose f era)
321+
where
322+
parseJSON = withObject "ConwayPlutusPurpose" $ \o -> do
323+
kind <- o .: "kind"
324+
value <- o .: "value"
325+
case (kind :: String) of
326+
"ConwaySpending" -> ConwaySpending <$> parseJSON value
327+
"ConwayMinting" -> ConwayMinting <$> parseJSON value
328+
"ConwayCertifying" -> ConwayCertifying <$> parseJSON value
329+
"ConwayRewarding" -> ConwayRewarding <$> parseJSON value
330+
"ConwayVoting" -> ConwayVoting <$> parseJSON value
331+
"ConwayProposing" -> ConwayProposing <$> parseJSON value
332+
_ -> fail $ "Unknown ConwayPlutusPurpose kind: " <> kind
333+
315334
pattern VotingPurpose ::
316335
ConwayEraScript era => f Word32 Voter -> PlutusPurpose f era
317336
pattern VotingPurpose c <- (toVotingPurpose -> Just c)

0 commit comments

Comments
 (0)