11{-# LANGUAGE AllowAmbiguousTypes #-}
22{-# LANGUAGE KindSignatures #-}
3+ {-# LANGUAGE LambdaCase #-}
34{-# LANGUAGE RankNTypes #-}
45{-# LANGUAGE ScopedTypeVariables #-}
56{-# LANGUAGE TypeApplications #-}
@@ -23,6 +24,7 @@ module Cardano.Ledger.Huddle.Gen (
2324 genBytesTerm ,
2425 genStringTerm ,
2526 genMapTerm ,
27+ canonicalizeTerm ,
2628 unwrapSingleOrError ,
2729
2830 -- * Term validators
@@ -53,10 +55,11 @@ import Codec.CBOR.Cuddle.CBOR.Gen (generateFromGRef, generateFromName)
5355import Codec.CBOR.Cuddle.CBOR.Validator (validateFromGRef , validateFromName )
5456import Codec.CBOR.Cuddle.CDDL (Name (.. ))
5557import Codec.CBOR.Cuddle.CDDL.CBORGenerator as CBORGen
56- import Control.Monad.Reader (asks )
5758import Codec.CBOR.Cuddle.CDDL.CTree (nintMin , uintMax )
59+ import Control.Monad.Reader (asks )
5860import Data.ByteString (ByteString )
5961import qualified Data.ByteString.Lazy as LBS
62+ import Data.List (sortOn )
6063import Data.Proxy (Proxy (.. ))
6164import Data.Text (Text )
6265import qualified Data.Text as T
@@ -65,6 +68,7 @@ import GHC.TypeLits (symbolVal)
6568import Test.AntiGen as AntiGen
6669import qualified Test.QuickCheck as QC
6770import Test.QuickCheck.GenT as GenT
71+ import Data.Bifunctor (Bifunctor (.. ))
6872
6973-- | A function for generating a term from a rule. The @HuddleRule@ constraint
7074-- ensures that the rule is actually defined in that era.
@@ -122,6 +126,34 @@ ifTwiddle yes no = do
122126 twiddle <- asks (gcTwiddle . geConfig)
123127 if twiddle then yes else no
124128
129+ -- | Fold each Term to its canonical CBOR form: definite-length variants,
130+ -- strict bytestrings/text, sorted map keys, and Int promoted to Integer.
131+ -- Two Terms that round-trip to the same Haskell value should compare equal
132+ -- after canonicalization.
133+ canonicalizeTerm :: Term -> Term
134+ canonicalizeTerm = \ case
135+ TInt n -> TInteger (toInteger n)
136+ TInteger n -> TInteger n
137+ TBytes bs -> TBytes bs
138+ TBytesI bs -> TBytes (LBS. toStrict bs)
139+ TString t -> TString t
140+ TStringI t -> TString (LT. toStrict t)
141+ TList xs -> TList (canonicalizeTerm <$> xs)
142+ TListI xs -> TList (canonicalizeTerm <$> xs)
143+ TMap kvs -> TMap (canonicalizeKVs kvs)
144+ TMapI kvs -> TMap (canonicalizeKVs kvs)
145+ TTagged tag t -> TTagged tag (canonicalizeTerm t)
146+ TBool b -> TBool b
147+ TNull -> TNull
148+ TSimple w -> TSimple w
149+ THalf f -> THalf f
150+ TFloat f -> TFloat f
151+ TDouble d -> TDouble d
152+ where
153+ canonicalizeKVs =
154+ sortOn fst
155+ . fmap (bimap canonicalizeTerm canonicalizeTerm)
156+
125157-- Term validators
126158
127159validateInt :: Term -> CBORValidator Integer
0 commit comments