|
| 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 qualified System.Process.ByteString.Lazy as P |
| 18 | + |
| 19 | +-- TODO: this is waiting to update to a newer ledger |
| 20 | +-- import qualified Test.Cardano.Chain.Binary.Cddl as Byron |
| 21 | + |
| 22 | +import System.IO |
| 23 | +import System.IO.Temp |
| 24 | +import qualified Test.Cardano.Ledger.Allegra.Binary.Cddl as Allegra |
| 25 | +import qualified Test.Cardano.Ledger.Alonzo.Binary.Cddl as Alonzo |
| 26 | +import qualified Test.Cardano.Ledger.Babbage.Binary.Cddl as Babbage |
| 27 | +import qualified Test.Cardano.Ledger.Conway.Binary.Cddl as Conway |
| 28 | +import qualified Test.Cardano.Ledger.Mary.Binary.Cddl as Mary |
| 29 | +import qualified Test.Cardano.Ledger.Shelley.Binary.Cddl as Shelley |
| 30 | +import Test.Tasty |
| 31 | + |
| 32 | +newtype CDDLSpec = CDDLSpec {cddlSpec :: BS.ByteString} deriving Show |
| 33 | + |
| 34 | +withCDDLs :: TestTree -> TestTree |
| 35 | +withCDDLs f = |
| 36 | + withResource |
| 37 | + ( do |
| 38 | + probeTools |
| 39 | + setupCDDLCEnv |
| 40 | + BS.writeFile "ntnblock.cddl" . cddlSpec |
| 41 | + =<< (cddlc "cddl/node-to-node/blockfetch/block.cddl" >>= fixupBlockCDDL) |
| 42 | + BS.writeFile "ntnheader.cddl" . cddlSpec |
| 43 | + =<< cddlc "cddl/node-to-node/chainsync/header.cddl" |
| 44 | + ) |
| 45 | + ( \() -> do |
| 46 | + D.removeFile "ntnblock.cddl" |
| 47 | + D.removeFile "ntnheader.cddl" |
| 48 | + ) |
| 49 | + (\_ -> f) |
| 50 | + |
| 51 | +fixupBlockCDDL :: CDDLSpec -> IO CDDLSpec |
| 52 | +fixupBlockCDDL spec = |
| 53 | + withTempFile "." "block-temp.cddl" $ \fp h -> do |
| 54 | + hClose h |
| 55 | + BS.writeFile fp . cddlSpec $ spec |
| 56 | + -- This is wrong, both the metadata_hash of a pool and a transaction body |
| 57 | + -- point to this type, but only the latter must be 32B. |
| 58 | + sed fp ["-i", "s/\\(metadata_hash = \\)/\\1 bytes ;/g"] |
| 59 | + -- For plutus, the type is actually `bytes`, but the distinct construct is |
| 60 | + -- for forcing generation of different values. |
| 61 | + sed fp ["-i", "s/\\(conway\\.distinct_VBytes = \\)/\\1 bytes ;\\//g"] |
| 62 | + -- These 3 below are hardcoded for generation. See cardano-ledger#5054 |
| 63 | + sed fp ["-i", "s/\\([yaoye]\\.address = \\)/\\1 bytes ;/g"] |
| 64 | + sed fp ["-i", "s/\\(reward_account = \\)/\\1 bytes ;/g"] |
| 65 | + sed |
| 66 | + fp |
| 67 | + [ "-i" |
| 68 | + , "-z" |
| 69 | + , "s/unit_interval = #6\\.30(\\[\\n\\s*1,\\n\\s*2,\\n\\])/unit_interval = #6.30([uint, uint])/g" |
| 70 | + ] |
| 71 | + CDDLSpec <$> BS.readFile fp |
| 72 | + |
| 73 | +setupCDDLCEnv :: IO () |
| 74 | +setupCDDLCEnv = do |
| 75 | + -- This is not how it should be because we can't update the Ledger |
| 76 | + -- to a newer one. On `master` there is a function |
| 77 | + -- `Byron.readByronCddlFileNames` which we would want to use. |
| 78 | + -- |
| 79 | + -- Note also that cabal run will run in the root of the project and |
| 80 | + -- cabal test will run in `ouroboros-consensus-cardano`. This path |
| 81 | + -- is for the latter. |
| 82 | + byron <- pure ["../../cardano-ledger/eras/byron/cddl-spec/"] |
| 83 | + shelley <- map takePath <$> Shelley.readShelleyCddlFileNames |
| 84 | + allegra <- map takePath <$> Allegra.readAllegraCddlFileNames |
| 85 | + mary <- map takePath <$> Mary.readMaryCddlFileNames |
| 86 | + alonzo <- map takePath <$> Alonzo.readAlonzoCddlFileNames |
| 87 | + babbage <- map takePath <$> Babbage.readBabbageCddlFileNames |
| 88 | + conway <- map takePath <$> Conway.readConwayCddlFileNames |
| 89 | + |
| 90 | + localDataDir <- takePath <$> getDataDir |
| 91 | + let local_paths = |
| 92 | + map |
| 93 | + (localDataDir F.</>) |
| 94 | + [ "cddl" |
| 95 | + , "cddl/disk" |
| 96 | + , "cddl/disk/snapshot" |
| 97 | + , "cddl/node-to-client/localstatequery/byron" |
| 98 | + , "cddl/node-to-client/localstatequery/consensus" |
| 99 | + , "cddl/node-to-client/localstatequery/shelley" |
| 100 | + , "cddl/node-to-client/txmonitor" |
| 101 | + ] |
| 102 | + |
| 103 | + include_path = |
| 104 | + mconcat $ |
| 105 | + L.intersperse ":" $ |
| 106 | + map (mconcat . L.intersperse ":") [byron, shelley, allegra, mary, alonzo, babbage, conway] |
| 107 | + <> local_paths |
| 108 | + |
| 109 | + writeFile "env" ("CDDL_INCLUDE_PATH=" <> include_path <> ":") |
| 110 | + E.setEnv "CDDL_INCLUDE_PATH" (include_path <> ":") |
| 111 | + |
| 112 | +sed :: FilePath -> [String] -> IO () |
| 113 | +sed fp args = |
| 114 | + Monad.void $ P.readProcessWithExitCode "sed" (args ++ [fp]) mempty |
| 115 | + |
| 116 | +{- FOURMOLU_DISABLE -} |
| 117 | + |
| 118 | +cddlc :: FilePath -> IO CDDLSpec |
| 119 | +cddlc dataFile = do |
| 120 | + putStrLn $ "Generating: " <> dataFile |
| 121 | + path <- getDataFileName dataFile |
| 122 | + (_, BSL.toStrict -> cddl, BSL.toStrict -> err) <- |
| 123 | +#ifdef POSIX |
| 124 | + P.readProcessWithExitCode "cddlc" ["-u", "-2", "-t", "cddl", path] mempty |
| 125 | +#else |
| 126 | + -- we cannot call @cddlc@ directly because it is not an executable in |
| 127 | + -- Haskell eyes, but we can call @ruby@ and pass the @cddlc@ script path as |
| 128 | + -- an argument |
| 129 | + do |
| 130 | + prefix <- E.getEnv "MSYSTEM_PREFIX" |
| 131 | + P.readProcessWithExitCode "ruby" [prefix F.</> "bin/cddlc", "-u", "-2", "-t", "cddl", path] mempty |
| 132 | +#endif |
| 133 | + Monad.unless (BS.null err) $ red $ BS8.unpack err |
| 134 | + return $ CDDLSpec cddl |
| 135 | + where |
| 136 | + red s = putStrLn $ "\ESC[31m" <> s <> "\ESC[0m" |
| 137 | + |
| 138 | +takePath :: FilePath -> FilePath |
| 139 | +takePath x = |
| 140 | +#ifdef POSIX |
| 141 | + F.takeDirectory x |
| 142 | +#else |
| 143 | + -- @cddlc@ is not capable of using backlashes |
| 144 | + -- |
| 145 | + -- @cddlc@ mixes @C:@ with the separator in @CDDL_INCLUDE_PATH@, and it |
| 146 | + -- doesn't understand @;@ as a separator. It works if we remove @C:@ and we |
| 147 | + -- are running in the same drive as the cddl files. |
| 148 | + let f = [ if c /= '\\' then c else '/' | c <- F.takeDirectory x ] |
| 149 | + in if "C:" `L.isPrefixOf` f |
| 150 | + then drop 2 f |
| 151 | + else f |
| 152 | +#endif |
| 153 | + |
| 154 | +probeTools :: IO () |
| 155 | +probeTools = do |
| 156 | + putStrLn "Probing tools:" |
| 157 | +#ifdef POSIX |
| 158 | + posixProbeTool "cddlc" "install the `cddlc` ruby gem" |
| 159 | + where |
| 160 | + posixProbeTool :: String -> Sring -> IO () |
| 161 | + posixProbeTool tool suggestion = do |
| 162 | + putStr $ "- " <> tool <> " " |
| 163 | + exe <- D.findExecutable tool |
| 164 | + if isNothing exe |
| 165 | + then do |
| 166 | + putStrLn "not found!" |
| 167 | + putStrLn $ "Please " <> suggestion |
| 168 | + exitFailure |
| 169 | + else |
| 170 | + putStrLn "found" |
| 171 | +#else |
| 172 | + -- On Windows, the cddl and cddlc files are POSIX scripts and therefore not |
| 173 | + -- recognized as executables by @findExecutable@, so we need to do some dirty |
| 174 | + -- tricks here. We check that ruby executable exists and then that there are |
| 175 | + -- cddl and cddlc files in the binary folder of the MSYS2 installation. |
| 176 | + putStr "- ruby " |
| 177 | + rubyExe <- D.findExecutable "ruby" |
| 178 | + if (isNothing rubyExe) |
| 179 | + then do |
| 180 | + putStrLn "not found!\nPlease install ruby" |
| 181 | + exitFailure |
| 182 | + else |
| 183 | + putStrLn "found" |
| 184 | + |
| 185 | + putStr "- cddlc " |
| 186 | + cddlcExe <- D.doesFileExist . (F.</> "bin/cddlc") =<< E.getEnv "MSYSTEM_PREFIX" |
| 187 | + if cddlcExe |
| 188 | + then putStrLn "found" |
| 189 | + else do |
| 190 | + putStrLn "not found!\nPlease install the `cddlc` ruby gem" |
| 191 | + exitFailure |
| 192 | + pure () |
| 193 | +#endif |
| 194 | + |
| 195 | +{- FOURMOLU_ENABLE -} |
0 commit comments