Skip to content

Commit 8fff707

Browse files
committed
Cardano CDDL tests
1 parent 7a9cacd commit 8fff707

File tree

5 files changed

+231
-9
lines changed

5 files changed

+231
-9
lines changed

ouroboros-consensus-cardano/ouroboros-consensus-cardano.cabal

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ test-suite cardano-test
438438
main-is: Main.hs
439439
other-modules:
440440
Test.Consensus.Cardano.DiffusionPipelining
441+
Test.Consensus.Cardano.GenCDDLs
441442
Test.Consensus.Cardano.Golden
442443
Test.Consensus.Cardano.MiniProtocol.LocalTxSubmission.ByteStringTxParser
443444
Test.Consensus.Cardano.MiniProtocol.LocalTxSubmission.Server
@@ -451,27 +452,34 @@ test-suite cardano-test
451452
Test.ThreadNet.MaryAlonzo
452453
Test.ThreadNet.ShelleyAllegra
453454

455+
other-modules: Paths_ouroboros_consensus_cardano
454456
build-depends:
455457
QuickCheck,
456458
base,
457459
base16-bytestring,
458460
bytestring,
461+
cardano-ledger-allegra:testlib,
459462
cardano-ledger-alonzo,
463+
cardano-ledger-alonzo:testlib,
460464
cardano-ledger-alonzo-test,
461465
cardano-ledger-api,
466+
cardano-ledger-babbage:testlib,
462467
cardano-ledger-babbage-test,
463468
cardano-ledger-binary:testlib,
464-
cardano-ledger-byron,
469+
cardano-ledger-byron:{cardano-ledger-byron, testlib},
465470
cardano-ledger-conway:testlib,
466471
cardano-ledger-core:{cardano-ledger-core, testlib},
472+
cardano-ledger-mary:testlib,
467473
cardano-ledger-shelley,
474+
cardano-ledger-shelley:testlib,
468475
cardano-ledger-shelley-test,
469476
cardano-protocol-tpraos,
470477
cardano-slotting,
471478
cborg,
472479
constraints,
473480
containers,
474481
contra-tracer,
482+
directory,
475483
filepath,
476484
microlens,
477485
ouroboros-consensus:{ouroboros-consensus, unstable-consensus-testlib, unstable-mempool-test-utils},
@@ -481,12 +489,14 @@ test-suite cardano-test
481489
ouroboros-network-api,
482490
ouroboros-network-protocols:{ouroboros-network-protocols, testlib},
483491
pretty-simple,
492+
process-extras,
484493
sop-core,
485494
sop-extras,
486495
strict-sop-core,
487496
tasty,
488497
tasty-hunit,
489498
tasty-quickcheck,
499+
temporary,
490500
typed-protocols ^>=0.3,
491501
unstable-byron-testlib,
492502
unstable-cardano-testlib,

ouroboros-consensus-cardano/test/cardano-test/Main.hs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module Main (main) where
22

33
import System.IO (BufferMode (LineBuffering), hSetBuffering, stdout)
44
import qualified Test.Consensus.Cardano.DiffusionPipelining
5+
import Test.Consensus.Cardano.GenCDDLs
56
import qualified Test.Consensus.Cardano.Golden
67
import qualified Test.Consensus.Cardano.MiniProtocol.LocalTxSubmission.Server
78
import qualified Test.Consensus.Cardano.Serialisation (tests)
@@ -29,8 +30,12 @@ tests =
2930
testGroup
3031
"cardano"
3132
[ Test.Consensus.Cardano.DiffusionPipelining.tests
32-
, Test.Consensus.Cardano.Golden.tests
33-
, Test.Consensus.Cardano.Serialisation.tests
33+
, withCDDLs $
34+
testGroup
35+
"Serialisation"
36+
[ Test.Consensus.Cardano.Golden.tests
37+
, Test.Consensus.Cardano.Serialisation.tests
38+
]
3439
, Test.Consensus.Cardano.SupportedNetworkProtocolVersion.tests
3540
, Test.Consensus.Cardano.SupportsSanityCheck.tests
3641
, Test.ThreadNet.AllegraMary.tests
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
{-# LANGUAGE CPP #-}
2+
{-# LANGUAGE ViewPatterns #-}
3+
4+
module Test.Consensus.Cardano.GenCDDLs (withCDDLs) where
5+
6+
import qualified Control.Monad as Monad
7+
import qualified Data.ByteString as BS
8+
import qualified Data.ByteString.Char8 as BS8
9+
import qualified Data.ByteString.Lazy as BSL
10+
import qualified Data.List as L
11+
import Data.Maybe (isNothing)
12+
import Paths_ouroboros_consensus_cardano
13+
import qualified System.Directory as D
14+
import qualified System.Environment as E
15+
import System.Exit
16+
import qualified System.FilePath as F
17+
import System.IO
18+
import System.IO.Temp
19+
import qualified System.Process.ByteString.Lazy as P
20+
import qualified Test.Cardano.Chain.Binary.Cddl as Byron
21+
import qualified Test.Cardano.Ledger.Allegra.Binary.Cddl as Allegra
22+
import qualified Test.Cardano.Ledger.Alonzo.Binary.Cddl as Alonzo
23+
import qualified Test.Cardano.Ledger.Babbage.Binary.Cddl as Babbage
24+
import qualified Test.Cardano.Ledger.Conway.Binary.Cddl as Conway
25+
import qualified Test.Cardano.Ledger.Mary.Binary.Cddl as Mary
26+
import qualified Test.Cardano.Ledger.Shelley.Binary.Cddl as Shelley
27+
import Test.Tasty
28+
29+
newtype CDDLSpec = CDDLSpec {cddlSpec :: BS.ByteString} deriving Show
30+
31+
-- | This function will run the provided test-tree after generating the node to
32+
-- node cddls for Blocks and Headers. As more CDDLs are stabilized they will
33+
-- have to be added here. Eventually we can have a datatype with one field for
34+
-- each CDDL so that we know always what is available.
35+
withCDDLs :: TestTree -> TestTree
36+
withCDDLs f =
37+
withResource
38+
( do
39+
probeTools
40+
setupCDDLCEnv
41+
42+
ntnBlock <- cddlc "cddl/node-to-node/blockfetch/block.cddl"
43+
ntnBlock' <- fixupBlockCDDL ntnBlock
44+
BS.writeFile "ntnblock.cddl" . cddlSpec $ ntnBlock'
45+
46+
ntnHeader <- cddlc "cddl/node-to-node/chainsync/header.cddl"
47+
BS.writeFile "ntnheader.cddl" . cddlSpec $ ntnHeader
48+
)
49+
( \() -> do
50+
D.removeFile "ntnblock.cddl"
51+
D.removeFile "ntnheader.cddl"
52+
)
53+
(\_ -> f)
54+
55+
-- | The Ledger CDDL specs are not _exactly_ correct. Here we do some dirty
56+
-- sed-replace to make them able to validate blocks. See cardano-ledger#5054.
57+
fixupBlockCDDL :: CDDLSpec -> IO CDDLSpec
58+
fixupBlockCDDL spec =
59+
withTempFile "." "block-temp.cddl" $ \fp h -> do
60+
hClose h
61+
BS.writeFile fp . cddlSpec $ spec
62+
-- For plutus, the type is actually `bytes`, but the distinct construct is
63+
-- for forcing generation of different values. See cardano-ledger#5054
64+
sed fp ["-i", "s/\\(conway\\.distinct_VBytes = \\)/\\1 bytes ;\\//g"]
65+
-- These 3 below are hardcoded for generation. See cardano-ledger#5054
66+
sed fp ["-i", "s/\\([yaoye]\\.address = \\)/\\1 bytes ;/g"]
67+
sed fp ["-i", "s/\\(reward_account = \\)/\\1 bytes ;/g"]
68+
sed
69+
fp
70+
[ "-i"
71+
, "-z"
72+
, "s/unit_interval = #6\\.30(\\[\\n\\s*1,\\n\\s*2,\\n\\])/unit_interval = #6.30([uint, uint])/g"
73+
]
74+
75+
sed fp ["-i", "s/\\(chain_code: bytes\\)/\\1, ;/g"]
76+
CDDLSpec <$> BS.readFile fp
77+
78+
-- | This sets the environment variables needed for `cddlc` to run properly.
79+
setupCDDLCEnv :: IO ()
80+
setupCDDLCEnv = do
81+
byron <- map takePath <$> Byron.readByronCddlFileNames
82+
shelley <- map takePath <$> Shelley.readShelleyCddlFileNames
83+
allegra <- map takePath <$> Allegra.readAllegraCddlFileNames
84+
mary <- map takePath <$> Mary.readMaryCddlFileNames
85+
alonzo <- map takePath <$> Alonzo.readAlonzoCddlFileNames
86+
babbage <- map takePath <$> Babbage.readBabbageCddlFileNames
87+
conway <- map takePath <$> Conway.readConwayCddlFileNames
88+
89+
localDataDir <- takePath <$> getDataDir
90+
let local_paths =
91+
map
92+
(localDataDir F.</>)
93+
["cddl"] -- Directories with other cddls that we import should go here
94+
include_path =
95+
mconcat $
96+
L.intersperse ":" $
97+
map (mconcat . L.intersperse ":") [byron, shelley, allegra, mary, alonzo, babbage, conway]
98+
<> local_paths
99+
100+
E.setEnv "CDDL_INCLUDE_PATH" (include_path <> ":")
101+
102+
-- | Call @sed@ on the given file with the given args
103+
sed :: FilePath -> [String] -> IO ()
104+
sed fp args =
105+
Monad.void $ P.readProcessWithExitCode "sed" (args ++ [fp]) mempty
106+
107+
{- FOURMOLU_DISABLE -}
108+
109+
cddlc :: FilePath -> IO CDDLSpec
110+
cddlc dataFile = do
111+
putStrLn $ "Generating: " <> dataFile
112+
path <- getDataFileName dataFile
113+
(_, BSL.toStrict -> cddl, BSL.toStrict -> err) <-
114+
#ifdef mingw32_HOST_OS
115+
-- we cannot call @cddlc@ directly because it is not an executable in
116+
-- Haskell eyes, but we can call @ruby@ and pass the @cddlc@ script path as
117+
-- an argument
118+
do
119+
prefix <- E.getEnv "MSYSTEM_PREFIX"
120+
P.readProcessWithExitCode "ruby" [prefix F.</> "bin/cddlc", "-u", "-2", "-t", "cddl", path] mempty
121+
#else
122+
P.readProcessWithExitCode "cddlc" ["-u", "-2", "-t", "cddl", path] mempty
123+
#endif
124+
Monad.unless (BS.null err) $ red $ BS8.unpack err
125+
return $ CDDLSpec cddl
126+
where
127+
red s = putStrLn $ "\ESC[31m" <> s <> "\ESC[0m"
128+
129+
takePath :: FilePath -> FilePath
130+
takePath x =
131+
#ifdef mingw32_HOST_OS
132+
-- @cddlc@ is not capable of using backlashes
133+
--
134+
-- @cddlc@ mixes @C:@ with the separator in @CDDL_INCLUDE_PATH@, and it
135+
-- doesn't understand @;@ as a separator. It works if we remove @C:@ and we
136+
-- are running in the same drive as the cddl files.
137+
let f = [ if c /= '\\' then c else '/' | c <- F.takeDirectory x ]
138+
in if "C:" `L.isPrefixOf` f
139+
then drop 2 f
140+
else f
141+
#else
142+
F.takeDirectory x
143+
#endif
144+
145+
probeTools :: IO ()
146+
probeTools = do
147+
putStrLn "Probing tools:"
148+
#ifdef mingw32_HOST_OS
149+
-- On Windows, the cddl and cddlc files are POSIX scripts and therefore not
150+
-- recognized as executables by @findExecutable@, so we need to do some dirty
151+
-- tricks here. We check that ruby executable exists and then that there are
152+
-- cddl and cddlc files in the binary folder of the MSYS2 installation.
153+
putStr "- ruby "
154+
rubyExe <- D.findExecutable "ruby"
155+
if (isNothing rubyExe)
156+
then do
157+
putStrLn "not found!\nPlease install ruby"
158+
exitFailure
159+
else
160+
putStrLn "found"
161+
162+
putStr "- cddlc "
163+
cddlcExe <- D.doesFileExist . (F.</> "bin/cddlc") =<< E.getEnv "MSYSTEM_PREFIX"
164+
if cddlcExe
165+
then putStrLn "found"
166+
else do
167+
putStrLn "not found!\nPlease install the `cddlc` ruby gem"
168+
exitFailure
169+
pure ()
170+
#else
171+
posixProbeTool "cddlc" "install the `cddlc` ruby gem"
172+
where
173+
posixProbeTool :: String -> String -> IO ()
174+
posixProbeTool tool suggestion = do
175+
putStr $ "- " <> tool <> " "
176+
exe <- D.findExecutable tool
177+
if isNothing exe
178+
then do
179+
putStrLn "not found!"
180+
putStrLn $ "Please " <> suggestion
181+
exitFailure
182+
else
183+
putStrLn "found"
184+
#endif
185+
186+
{- FOURMOLU_ENABLE -}

ouroboros-consensus-cardano/test/cardano-test/Test/Consensus/Cardano/Golden.hs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{-# LANGUAGE FlexibleContexts #-}
22
{-# LANGUAGE FlexibleInstances #-}
3+
{-# LANGUAGE OverloadedStrings #-}
34
{-# LANGUAGE TemplateHaskell #-}
45
{-# LANGUAGE TypeFamilies #-}
56
{-# OPTIONS_GHC -Wno-orphans #-}
@@ -16,10 +17,16 @@ import System.FilePath ((</>))
1617
import Test.Consensus.Cardano.Examples
1718
import Test.Tasty
1819
import Test.Util.Paths
20+
import Test.Util.Serialisation.CDDL
1921
import Test.Util.Serialisation.Golden
2022

2123
tests :: TestTree
22-
tests = goldenTest_all codecConfig ($(getGoldenDir) </> "cardano") examples
24+
tests =
25+
goldenTest_all
26+
codecConfig
27+
($(getGoldenDir) </> "cardano")
28+
(Just $ CDDLsForNodeToNode ("ntnblock.cddl", "serialisedCardanoBlock") ("ntnheader.cddl", "header"))
29+
examples
2330

2431
instance
2532
CardanoHardForkConstraints c =>

ouroboros-consensus-cardano/test/cardano-test/Test/Consensus/Cardano/Serialisation.hs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{-# LANGUAGE GADTs #-}
22
{-# LANGUAGE LambdaCase #-}
33
{-# LANGUAGE NamedFieldPuns #-}
4+
{-# LANGUAGE OverloadedStrings #-}
45
{-# LANGUAGE ScopedTypeVariables #-}
56

67
module Test.Consensus.Cardano.Serialisation (tests) where
@@ -21,7 +22,6 @@ import Ouroboros.Network.Block (Serialised (..))
2122
import Test.Consensus.Byron.Generators (epochSlots)
2223
import qualified Test.Consensus.Cardano.Examples as Cardano.Examples
2324
import Test.Consensus.Cardano.Generators ()
24-
import Test.Consensus.Cardano.MockCrypto (MockCryptoCompatByron)
2525
import Test.Tasty
2626
import Test.Tasty.QuickCheck (Property, testProperty, (===))
2727
import Test.Util.Orphans.Arbitrary ()
@@ -33,15 +33,29 @@ tests =
3333
"Cardano"
3434
[ testGroup "Examples roundtrip" $
3535
examplesRoundtrip Cardano.Examples.codecConfig Cardano.Examples.examples
36-
, roundtrip_all_skipping result testCodecCfg dictNestedHdr
36+
, roundtrip_all_skipping
37+
result
38+
testCodecCfg
39+
dictNestedHdr
40+
-- We would want to use this instead, but the generated blocks
41+
-- do not quite validate yet or sometimes they are not
42+
-- entirely coherent, so for now this is commented out.
43+
--
44+
-- It is also the case that some (conway in particular) blocks take a
45+
-- very long time to validate or consume too much memory.
46+
--
47+
-- ( Just $
48+
-- CDDLsForNodeToNode ("ntnblock.cddl", "serialisedCardanoBlock") ("ntnheader.cddl", "header")
49+
-- )
50+
Nothing
3751
, testProperty "BinaryBlockInfo sanity check" prop_CardanoBinaryBlockInfo
3852
]
3953
where
4054
-- See https://github.com/IntersectMBO/cardano-ledger/issues/3800
4155
result "roundtrip Result" = DoNotCheckCBORValidity
4256
result _ = CheckCBORValidity
4357

44-
testCodecCfg :: CardanoCodecConfig MockCryptoCompatByron
58+
testCodecCfg :: CardanoCodecConfig StandardCrypto
4559
testCodecCfg =
4660
CardanoCodecConfig
4761
(ByronCodecConfig epochSlots)
@@ -54,7 +68,7 @@ testCodecCfg =
5468

5569
dictNestedHdr ::
5670
forall a.
57-
NestedCtxt_ (CardanoBlock MockCryptoCompatByron) Header a ->
71+
NestedCtxt_ (CardanoBlock StandardCrypto) Header a ->
5872
Dict (Eq a, Show a)
5973
dictNestedHdr = \case
6074
NCZ (CtxtByronBoundary{}) -> Dict
@@ -70,7 +84,7 @@ dictNestedHdr = \case
7084
BinaryBlockInfo
7185
-------------------------------------------------------------------------------}
7286

73-
prop_CardanoBinaryBlockInfo :: CardanoBlock MockCryptoCompatByron -> Property
87+
prop_CardanoBinaryBlockInfo :: CardanoBlock StandardCrypto -> Property
7488
prop_CardanoBinaryBlockInfo blk =
7589
encodedNestedHeader === extractedHeader
7690
where

0 commit comments

Comments
 (0)