Skip to content

Commit

Permalink
Write test for TxWits deserialization and run it in each post-alonzo era
Browse files Browse the repository at this point in the history
  • Loading branch information
teodanciu committed Dec 21, 2023
1 parent 0486f0f commit 625d7c5
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 0 deletions.
1 change: 1 addition & 0 deletions eras/alonzo/impl/cardano-ledger-alonzo.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ library testlib
Test.Cardano.Ledger.Alonzo.Binary.Cddl
Test.Cardano.Ledger.Alonzo.Binary.CostModelsSpec
Test.Cardano.Ledger.Alonzo.Binary.RoundTrip
Test.Cardano.Ledger.Alonzo.Binary.TxWitsSpec
Test.Cardano.Ledger.Alonzo.CostModel
Test.Cardano.Ledger.Alonzo.ImpTest
Test.Cardano.Ledger.Alonzo.TreeDiff
Expand Down
3 changes: 3 additions & 0 deletions eras/alonzo/impl/test/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Cardano.Ledger.Alonzo (Alonzo)
import Data.Proxy (Proxy (Proxy))
import qualified Test.Cardano.Ledger.Alonzo.Binary.CddlSpec as CddlSpec
import qualified Test.Cardano.Ledger.Alonzo.Binary.CostModelsSpec as CostModelsSpec
import qualified Test.Cardano.Ledger.Alonzo.Binary.TxWitsSpec as TxWitsSpec
import qualified Test.Cardano.Ledger.Alonzo.BinarySpec as BinarySpec
import Test.Cardano.Ledger.Alonzo.ImpTest ()
import Test.Cardano.Ledger.Common
Expand All @@ -21,3 +22,5 @@ main =
ShelleyImp.spec @Alonzo
describe "CostModels" $ do
CostModelsSpec.spec @Alonzo Proxy
describe "TxWits" $ do
TxWitsSpec.spec @Alonzo Proxy
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

module Test.Cardano.Ledger.Alonzo.Binary.TxWitsSpec (spec) where

import Cardano.Ledger.Alonzo.Core
import Cardano.Ledger.Alonzo.Scripts
import Cardano.Ledger.Alonzo.TxWits (AlonzoTxWits (..))
import Cardano.Ledger.BaseTypes
import Cardano.Ledger.Binary (DeserialiseFailure (..))
import Cardano.Ledger.Binary.Decoding
import Cardano.Ledger.Binary.Encoding
import Cardano.Ledger.Keys
import Cardano.Ledger.Plutus.Language
import Data.List (isPrefixOf)
import qualified Data.Map as Map
import qualified Data.Maybe as Maybe (mapMaybe)
import Data.Typeable
import Test.Cardano.Ledger.Alonzo.Arbitrary
import Test.Cardano.Ledger.Common

spec ::
forall era.
( AlonzoEraScript era
, Script era ~ AlonzoScript era
) =>
Proxy era ->
Spec
spec pxy = do
describe "AlonzoTxWits deserialization" $ do
describe "plutus scripts" $ do
plutusScriptsProp @era pxy
describe "native scripts" $ do
nativeScriptsProp @era pxy
describe "vkeys" $ do
vkeysProp @era pxy

vkeysProp ::
forall era.
AlonzoEraScript era =>
Proxy era ->
Spec
vkeysProp pxy = do
prop "fails to deserialize if empty, starting with Conway" $
distinctProp -- .&. emptyProp
where
key :: Int = 0
distinctProp =
forAllShow (genEncoding False) (showEnc pxy) $
expectDeserialiseSuccess pxy

-- TODO: enable this after we enforce distinct entries for Annotator
-- duplicateProp =
-- forAllShow (genEncoding True) (showEnc pxy) $
-- \enc ->
-- expectDeserialiseFailureFromVersion
-- pxy
-- (natVersion @9)
-- enc
-- "Final number of elements"

-- emptyProp =
-- let emptyScriptsEnc = encCBOR $ Map.singleton key (encCBOR ([] :: [Encoding]))
-- in property $
-- expectDeserialiseFailureFromVersion
-- pxy
-- (natVersion @9)
-- emptyScriptsEnc
-- unexpectedEmptyError

genEncoding :: Bool -> Gen Encoding
genEncoding duplicate = do
sc <- arbitrary :: Gen (WitVKey 'Witness (EraCrypto era))
let scs
| duplicate = [sc, sc]
| otherwise = [sc]

pure $ encCBOR $ Map.singleton key (encCBOR scs)

nativeScriptsProp ::
forall era.
( AlonzoEraScript era
, Script era ~ AlonzoScript era
) =>
Proxy era ->
Spec
nativeScriptsProp pxy = do
prop "fails to deserialize if empty, starting with Conway" $
distinctProp .&. emptyProp
where
key :: Int = 1
distinctProp =
forAllShow (genEncoding False) (showEnc pxy) $
expectDeserialiseSuccess pxy

-- TODO: enable this after we enforce distinct entries for Annotator
-- duplicateProp =
-- forAllShow (genEncoding True) (showEnc pxy) $
-- \enc ->
-- expectDeserialiseFailureFromVersion
-- pxy
-- (natVersion @9)
-- enc
-- unexpectedDuplicatesError

emptyProp =
let emptyScriptsEnc = encCBOR $ Map.singleton key (encCBOR ([] :: [Encoding]))
in property $
expectDeserialiseFailureFromVersion
pxy
(natVersion @9)
emptyScriptsEnc
unexpectedEmptyError

genEncoding :: Bool -> Gen Encoding
genEncoding duplicate = do
sc <- genNativeScript @era
let scs
| duplicate = [sc, sc]
| otherwise = [sc]

let natives = Maybe.mapMaybe getNativeScript scs
pure $ encCBOR $ Map.singleton key (encCBOR natives)

plutusScriptsProp ::
forall era.
( AlonzoEraScript era
, Script era ~ AlonzoScript era
) =>
Proxy era ->
Spec
plutusScriptsProp pxy = do
prop "fails to deserialize if empty or if it contains duplicates, starting with Conway" $
conjoin $
[ distinctProp
, duplicateProp
, emptyProp
]
<*> [minBound .. eraMaxLanguage @era]
where
distinctProp lang =
forAllShow (genEncoding lang False) (showEnc pxy) $
expectDeserialiseSuccess pxy

duplicateProp lang =
forAllShow (genEncoding lang True) (showEnc pxy) $
\enc ->
expectDeserialiseFailureFromVersion
pxy
(natVersion @9)
enc
unexpectedDuplicatesError

emptyProp lang =
let emptyScriptsEnc = encCBOR $ Map.singleton (keys lang) (encCBOR ([] :: [Encoding]))
in property $
expectDeserialiseFailureFromVersion
pxy
(natVersion @9)
emptyScriptsEnc
unexpectedEmptyError

genEncoding :: Language -> Bool -> Gen Encoding
genEncoding lang duplicate = do
sc <- genPlutusScript @era lang
let scs
| duplicate = [sc, sc]
| otherwise = [sc]
let plutusBins = withSLanguage lang $ \slang ->
Maybe.mapMaybe
(\x -> plutusBinary <$> (toPlutusScript x >>= toPlutusSLanguage slang))
scs
pure $ encCBOR $ Map.singleton (keys lang) (encCBOR plutusBins)
keys PlutusV1 = 3 :: Int
keys PlutusV2 = 6
keys PlutusV3 = 7

unexpectedEmptyError :: String
unexpectedEmptyError = "Empty list"

unexpectedDuplicatesError :: String
unexpectedDuplicatesError = "Final number of elements"

expectDeserialiseSuccess ::
forall era.
(AlonzoEraScript era, HasCallStack) =>
Proxy era ->
Encoding ->
IO ()
expectDeserialiseSuccess _ enc =
encodeAndCheckDecoded @era enc $
\decoded -> void $ expectRight decoded

expectDeserialiseFailureFromVersion ::
forall era.
(AlonzoEraScript era, HasCallStack) =>
Proxy era ->
Version ->
Encoding ->
String ->
IO ()
expectDeserialiseFailureFromVersion _ v enc errMsgPrefix =
encodeAndCheckDecoded @era enc $
\decoded -> do
if eraProtVerHigh @era < v
then void $ expectRight decoded
else expectDeserialiseFailure (void decoded) errMsgPrefix

expectDeserialiseFailure ::
(HasCallStack, Show t) =>
Either DecoderError t ->
String ->
IO ()
expectDeserialiseFailure e errMsgPrefix = do
res <- expectLeft e
res `shouldSatisfy` \case
DecoderErrorDeserialiseFailure _ (DeserialiseFailure _ errMsg) ->
errMsgPrefix `isPrefixOf` errMsg
_ -> False

encodeAndCheckDecoded ::
forall era.
AlonzoEraScript era =>
Encoding ->
(Either DecoderError (Annotator (AlonzoTxWits era)) -> IO ()) ->
IO ()
encodeAndCheckDecoded enc check = do
let ver = eraProtVerHigh @era
bytes = serialize ver enc
check (decodeFull @(Annotator (AlonzoTxWits era)) ver bytes)

showEnc :: forall era. Era era => Proxy era -> Encoding -> String
showEnc _ enc = show $ toPlainEncoding (eraProtVerHigh @era) enc
3 changes: 3 additions & 0 deletions eras/babbage/impl/test/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Main where
import Cardano.Ledger.Babbage (Babbage)
import Data.Proxy (Proxy (Proxy))
import qualified Test.Cardano.Ledger.Alonzo.Binary.CostModelsSpec as CostModelsSpec
import qualified Test.Cardano.Ledger.Alonzo.Binary.TxWitsSpec as TxWitsSpec
import qualified Test.Cardano.Ledger.Babbage.Binary.CddlSpec as CddlSpec
import qualified Test.Cardano.Ledger.Babbage.BinarySpec as BinarySpec
import Test.Cardano.Ledger.Babbage.ImpTest ()
Expand All @@ -21,3 +22,5 @@ main =
ShelleyImp.spec @Babbage
describe "CostModels" $ do
CostModelsSpec.spec @Babbage Proxy
describe "TxWits" $ do
TxWitsSpec.spec @Babbage Proxy
3 changes: 3 additions & 0 deletions eras/conway/impl/test/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Main where
import Cardano.Ledger.Conway (Conway)
import Data.Proxy (Proxy (..))
import qualified Test.Cardano.Ledger.Alonzo.Binary.CostModelsSpec as CostModelsSpec
import qualified Test.Cardano.Ledger.Alonzo.Binary.TxWitsSpec as TxWitsSpec
import Test.Cardano.Ledger.Common
import qualified Test.Cardano.Ledger.Conway.Binary.CddlSpec as Cddl
import qualified Test.Cardano.Ledger.Conway.BinarySpec as Binary
Expand Down Expand Up @@ -32,3 +33,5 @@ main =
ShelleyImp.spec @Conway
describe "CostModels" $ do
CostModelsSpec.spec @Conway Proxy
describe "TxWits" $ do
TxWitsSpec.spec @Conway Proxy

0 comments on commit 625d7c5

Please sign in to comment.