diff --git a/.changes/20261015_022558_cardano-api_palas_read_node_config_cardano_config.yml b/.changes/20261015_022558_cardano-api_palas_read_node_config_cardano_config.yml new file mode 100644 index 0000000000..62bf493341 --- /dev/null +++ b/.changes/20261015_022558_cardano-api_palas_read_node_config_cardano_config.yml @@ -0,0 +1,18 @@ +project: cardano-api +pr: 1379 +kind: +- breaking +description: | + `readNodeConfig` and `initialLedgerState` now read node configurations with cardano-config. They accept both the old flat format and the new cardano-config format. + `readNodeConfig` now also reads the genesis files, and genesis hashes are now required. + A configuration is also rejected if it sets `ExperimentalHardForksEnabled` without a `DijkstraGenesisFile`, or if its tracing section cannot be read. + With `ExperimentalHardForksEnabled`, the Dijkstra genesis that is used is the one that the configuration specifies, instead of the example one. + Without `ExperimentalHardForksEnabled`, `TestDijkstraHardForkAtEpoch` is now ignored, as in the node. + `readNodeConfig` now fails with a `NodeConfigError` instead of `Text`; it carries cardano-config's errors. + `readNodeConfig` now also returns cardano-config's warnings, such as unknown keys. + `NodeConfig` is now a newtype around cardano-config's `NodeConfiguration` (`ncConfiguration`); its old fields are now functions with the same names. + `NodeConfig` no longer has a `FromJSON` instance: use `readNodeConfig`. + `PBftSignatureThreshold` and `LastKnownBlockVersion-Major`/`-Minor`/`-Alt` are no longer read, so `ncPBftSignatureThreshold` is always `Nothing` (the consensus default) and `ncByronProtocolVersion` is always 1.0.0; both are deprecated. `cardano-api` does not use these two values when reading or applying blocks. + `readByronGenesisConfig`, `readShelleyGenesisConfig`, `readAlonzoGenesisConfig` and `readConwayGenesisConfig` are now plain functions of `NodeConfig`. + `ncByronGenesisHash`, `ncShelleyGenesisHash`, `ncAlonzoGenesisHash` and `ncConwayGenesisHash` now return the hash, not a `Maybe`. + `GenesisConfigError` keeps only `NECardanoConfig`. diff --git a/.gitattributes b/.gitattributes index 3f7c38230c..e07b8b6a33 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,6 @@ cardano-rpc/gen/** linguist-generated=true cardano-rpc/gen/** no-prettify +# Genesis hashes are taken over the raw file bytes, so a CRLF checkout on +# Windows would not match the hashes the node configuration tests pin. +cardano-api/test/cardano-api-test/files/input/node-config/*.json text eol=lf diff --git a/.github/workflows/haskell.yml b/.github/workflows/haskell.yml index c99b4ed6e5..a960d846c3 100644 --- a/.github/workflows/haskell.yml +++ b/.github/workflows/haskell.yml @@ -75,6 +75,30 @@ jobs: f+${{ matrix.sys.os }} g+${{ (startsWith(github.ref, 'refs/heads/gh-readonly-queue/') && github.run_id) || github.event.pull_request.number || github.ref }} + - name: "[macOS] Use the default Xcode's toolchain and SDK" + if: runner.os == 'macOS' + # The macos-26 image 20261013.0424 updated the Command Line Tools to 27.0, whose + # macOS 27 SDK the default Xcode's linker cannot read ("tapi error: malformed file", + # "unknown architecture arm64e.x1-macos"). Builds still reach that SDK through + # the Command Line Tools' MacOSX.sdk link even with SDKROOT set, so point that + # link at the default Xcode's SDK too. Remove once the image's toolchain and + # SDK match again. + run: | + developer_dir=/Applications/Xcode.app/Contents/Developer + sdkroot="$(DEVELOPER_DIR="$developer_dir" xcrun --sdk macosx --show-sdk-path)" + echo "DEVELOPER_DIR=$developer_dir" >> "$GITHUB_ENV" + echo "SDKROOT=$sdkroot" >> "$GITHUB_ENV" + echo "xcode-select -p: $(xcode-select -p)" + echo "Using DEVELOPER_DIR=$developer_dir SDKROOT=$sdkroot" + DEVELOPER_DIR="$developer_dir" xcrun ld -v 2>&1 | head -1 + clt_sdk=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk + ls -l /Library/Developer/CommandLineTools/SDKs/ + if [ -e "$clt_sdk" ] || [ -L "$clt_sdk" ]; then + sudo mv "$clt_sdk" "$clt_sdk.ci-original" + fi + sudo ln -s "$sdkroot" "$clt_sdk" + echo "$clt_sdk -> $(readlink "$clt_sdk")" + - name: Install Haskell uses: input-output-hk/actions/haskell@latest id: setup-haskell diff --git a/cabal.project b/cabal.project index 5a65908580..4153249fbe 100644 --- a/cabal.project +++ b/cabal.project @@ -14,7 +14,7 @@ repository cardano-haskell-packages -- you need to run if you change them index-state: , hackage.haskell.org 2026-09-02T14:05:07Z - , cardano-haskell-packages 2026-10-06T15:10:52Z + , cardano-haskell-packages 2026-10-16T09:27:03Z packages: cardano-api diff --git a/cardano-api/cardano-api.cabal b/cardano-api/cardano-api.cabal index f3fa784552..cff9a6870a 100644 --- a/cardano-api/cardano-api.cabal +++ b/cardano-api/cardano-api.cabal @@ -135,6 +135,7 @@ library cardano-addresses ^>=4.0.0, cardano-base ^>=0.1, cardano-binary, + cardano-config ^>=2.2.2, cardano-crypto, cardano-crypto-class ^>=2.6, cardano-crypto-wrapper ^>=1.8, @@ -204,7 +205,6 @@ library transformers-except ^>=0.1.3, typed-protocols ^>=1.2, validation, - yaml, other-modules: Cardano.Api.Byron.Internal.Key @@ -374,6 +374,7 @@ test-suite cardano-api-test cardano-api, cardano-api:gen, cardano-binary, + cardano-config, cardano-crypto, cardano-crypto-class:{cardano-crypto-class, testlib} ^>=2.6, cardano-crypto-wrapper:testlib, @@ -382,6 +383,7 @@ test-suite cardano-api-test cardano-ledger-api ^>=1.15, cardano-ledger-babbage, cardano-ledger-binary, + cardano-ledger-byron, cardano-ledger-conway, cardano-ledger-core:{cardano-ledger-core, testlib} >=1.22, cardano-ledger-dijkstra, @@ -395,6 +397,7 @@ test-suite cardano-api-test data-default, directory, filepath, + fs-api, hedgehog >=1.1, hedgehog-extras, hedgehog-quickcheck, diff --git a/cardano-api/src/Cardano/Api/LedgerState.hs b/cardano-api/src/Cardano/Api/LedgerState.hs index 289deabde8..2ccf899693 100644 --- a/cardano-api/src/Cardano/Api/LedgerState.hs +++ b/cardano-api/src/Cardano/Api/LedgerState.hs @@ -59,6 +59,7 @@ module Cardano.Api.LedgerState , FoldBlocksError (..) , GenesisConfigError (..) , InitialLedgerStateError (..) + , NodeConfigError (..) -- * Leadership schedule , LeadershipError (..) @@ -68,6 +69,18 @@ module Cardano.Api.LedgerState -- * Node Config , NodeConfig (..) + , ncPBftSignatureThreshold + , ncByronGenesisFile + , ncByronGenesisHash + , ncShelleyGenesisFile + , ncShelleyGenesisHash + , ncAlonzoGenesisFile + , ncAlonzoGenesisHash + , ncConwayGenesisFile + , ncConwayGenesisHash + , ncRequiresNetworkMagic + , ncByronProtocolVersion + , ncHardForkTriggers -- ** Network Config , NodeConfigFile @@ -146,10 +159,10 @@ import Cardano.Api.Tx.Internal.Body import Cardano.Binary qualified as CBOR import Cardano.Chain.Genesis qualified import Cardano.Chain.Update qualified +import Cardano.Configuration qualified as Cfg import Cardano.Crypto (ProtocolMagicId (unProtocolMagicId), RequiresNetworkMagic (..)) import Cardano.Crypto.Hash.Blake2b qualified import Cardano.Crypto.Hash.Class qualified -import Cardano.Crypto.Hashing qualified import Cardano.Crypto.ProtocolMagic qualified import Cardano.Crypto.VRF qualified as Crypto import Cardano.Crypto.VRF.Class qualified as VRF @@ -233,16 +246,7 @@ import Control.Monad.Class.MonadST (MonadST) import Control.Monad.Class.MonadThrow (MonadThrow) import Control.Monad.State.Strict import Control.Tracer qualified as Tracer -import Data.Aeson as Aeson - ( FromJSON (parseJSON) - , Object - , eitherDecodeStrict' - , withObject - , (.:) - , (.:?) - ) -import Data.Aeson qualified as A -import Data.Aeson.Types (Parser) +import Data.Aeson as Aeson (eitherDecodeStrict') import Data.Bifunctor import Data.ByteArray (ByteArrayAccess) import Data.ByteArray qualified @@ -251,7 +255,7 @@ import Data.ByteString qualified as BS import Data.ByteString.Base16 qualified as Base16 import Data.ByteString.Lazy qualified as LBS import Data.ByteString.Short as BSS -import Data.Foldable (asum) +import Data.Functor.Identity (Identity, runIdentity) import Data.IORef import Data.List qualified as List import Data.Map.Strict (Map) @@ -273,7 +277,6 @@ import Data.Text.Lazy qualified as LT import Data.Text.Lazy.Builder (toLazyText) import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds) import Data.Word -import Data.Yaml qualified as Yaml import Formatting.Buildable (build) import GHC.Exts (IsList (..)) import GHC.Stack (HasCallStack) @@ -373,7 +376,8 @@ initialLedgerState fs nodeConfigFile = do -- TODO Once support for querying the ledger config is added to the node, we -- can remove the nodeConfigFile argument and much of the code in this -- module. - config <- modifyError ILSEConfigFile (readNodeConfig nodeConfigFile) + (config, _warnings) <- + modifyError (ILSEConfigFile . docToText . prettyError) (readNodeConfig nodeConfigFile) genesisConfig <- modifyError ILSEGenesisFile (readCardanoGenesisConfig config) env <- hoistIOEither (first ILSELedgerConsensusConfig <$> genesisConfigToEnv fs genesisConfig) ledgerState <- liftIO (initLedgerStateVar fs genesisConfig) @@ -1109,152 +1113,196 @@ genesisConfigToEnv fs genCfg = where shelleyGenesis = transCfg ^. Ledger.tcShelleyGenesisL +-- | Why 'readNodeConfig' could not read a node configuration. +data NodeConfigError + = -- | @cardano-config@ could not read, decode or check the configuration or a + -- genesis file it names. The error says which file, section and key are at + -- fault. + NodeConfigParsingError Cfg.ConfigurationParsingError + | -- | @cardano-config@ read the configuration, but could not resolve it. + NodeConfigResolutionError Cfg.ConfigResolutionError + | -- | Any other failure while reading the configuration. @trace-dispatcher@, + -- which reads the tracing section, throws its own exceptions, and reading a + -- file can fail with an IO error. + NodeConfigOtherError SomeException + deriving Show + +instance Exception NodeConfigError + +instance Error NodeConfigError where + prettyError = \case + NodeConfigParsingError err -> prettyException err + NodeConfigResolutionError err -> prettyException err + NodeConfigOtherError (SomeException err) -> prettyException err + +-- | Read a node configuration file through @cardano-config@, in either the flat +-- format or the @cardano-config@ envelope. Every genesis file the +-- configuration names is read, decoded, and checked against the hash the +-- configuration gives for it, so a configuration without genesis hashes is +-- rejected. +-- +-- Also returns the warnings @cardano-config@ raised while reading the +-- configuration, for example about keys it does not know, or a configuration in +-- an older format. 'Cfg.renderConfigWarning' renders them. readNodeConfig - :: MonadError Text m + :: MonadError NodeConfigError m => MonadIO m => NodeConfigFile 'In - -> m NodeConfig + -> m (NodeConfig, [Cfg.ConfigWarning]) readNodeConfig (File ncf) = do - ncfg <- liftEither . parseNodeConfig =<< readByteString ncf "node" - return - ncfg - { ncByronGenesisFile = - mapFile (mkAdjustPath ncf) (ncByronGenesisFile ncfg) - , ncShelleyGenesisFile = - mapFile (mkAdjustPath ncf) (ncShelleyGenesisFile ncfg) - , ncAlonzoGenesisFile = - mapFile (mkAdjustPath ncf) (ncAlonzoGenesisFile ncfg) - , ncConwayGenesisFile = - mapFile (mkAdjustPath ncf) (ncConwayGenesisFile ncfg) - } - -data NodeConfig = NodeConfig - { ncPBftSignatureThreshold :: !(Maybe Double) - , ncByronGenesisFile :: !(File ByronGenesisConfig 'In) - , ncByronGenesisHash :: !(Maybe GenesisHashByron) - , ncShelleyGenesisFile :: !(File ShelleyGenesisConfig 'In) - , ncShelleyGenesisHash :: !(Maybe GenesisHashShelley) - , ncAlonzoGenesisFile :: !(File AlonzoGenesis 'In) - , ncAlonzoGenesisHash :: !(Maybe GenesisHashAlonzo) - , ncConwayGenesisFile :: !(File ConwayGenesisConfig 'In) - , ncConwayGenesisHash :: !(Maybe GenesisHashConway) - , ncRequiresNetworkMagic :: !Cardano.Crypto.RequiresNetworkMagic - , ncByronProtocolVersion :: !Cardano.Chain.Update.ProtocolVersion - , ncHardForkTriggers :: !Consensus.CardanoHardForkTriggers + (fromFile, fileWarnings) <- + liftEither . first readError <=< liftIO . tryAny $ + Cfg.parseConfigurationFiles ncf + -- The first argument of 'Cfg.resolveConfigurationWith' is the list of + -- consistency checks to run ('Cfg.resolveConfiguration' runs cardano-config's + -- default list, 'Cfg.defaultConfigChecks'). We run none: those checks are + -- about running a node (gRPC, connection limits, peer targets, snapshots), + -- and some need the node's command line, which we don't have here. + (nc, resolutionWarnings) <- + liftEither . first NodeConfigResolutionError $ + Cfg.resolveConfigurationWith [] (Cfg.defaultCliArgs ncf) fromFile + pure (NodeConfig nc, fileWarnings <> resolutionWarnings) + where + -- cardano-config throws a 'Cfg.ConfigurationParsingError', but it hands the + -- tracing section to trace-dispatcher, which throws yaml's @ParseException@ or + -- an 'ErrorCall' instead, and reading a file can fail with an IO error. + readError :: SomeException -> NodeConfigError + readError e = maybe (NodeConfigOtherError e) NodeConfigParsingError $ fromException e + +-- | The hard fork triggers of a testing configuration: for each era, the epoch +-- the configuration gives, and otherwise the era's default protocol version. +-- Like the node, it ignores the Dijkstra epoch unless +-- @ExperimentalHardForksEnabled@ is true. +hardForkTriggers + :: Cfg.TestingConfiguration Identity + -> Consensus.CardanoHardForkTriggers +hardForkTriggers testing = + Consensus.CardanoHardForkTriggers' + (atEpoch $ Cfg.testShelleyHardForkAtEpoch testing) + (atEpoch $ Cfg.testAllegraHardForkAtEpoch testing) + (atEpoch $ Cfg.testMaryHardForkAtEpoch testing) + (atEpoch $ Cfg.testAlonzoHardForkAtEpoch testing) + (atEpoch $ Cfg.testBabbageHardForkAtEpoch testing) + (atEpoch $ Cfg.testConwayHardForkAtEpoch testing) + (atEpoch dijkstraEpoch) + where + dijkstraEpoch + | runIdentity (Cfg.experimentalHardForksEnabled testing) = Cfg.testDijkstraHardForkAtEpoch testing + | otherwise = Ledger.SNothing + atEpoch :: Ledger.StrictMaybe Word64 -> Consensus.CardanoHardForkTrigger blk + atEpoch = + maybe + Consensus.CardanoTriggerHardForkAtDefaultVersion + (Consensus.CardanoTriggerHardForkAtEpoch . Slot.EpochNo) + . Ledger.strictMaybeToMaybe + +-- | A node configuration, as @cardano-config@ read it. The functions below give +-- the parts of it this library uses. +newtype NodeConfig = NodeConfig + { ncConfiguration :: Cfg.NodeConfiguration + -- ^ The configuration as @cardano-config@ read it, genesis files included. } -instance FromJSON NodeConfig where - parseJSON = - Aeson.withObject "NodeConfig" parse - where - parse :: Object -> Parser NodeConfig - parse o = - NodeConfig - <$> o .:? "PBftSignatureThreshold" - <*> fmap File (o .: "ByronGenesisFile") - <*> (fmap . fmap) GenesisHashByron (o .:? "ByronGenesisHash") - <*> fmap File (o .: "ShelleyGenesisFile") - <*> (fmap . fmap) GenesisHashShelley (o .:? "ShelleyGenesisHash") - <*> fmap File (o .: "AlonzoGenesisFile") - <*> (fmap . fmap) GenesisHashAlonzo (o .:? "AlonzoGenesisHash") - <*> fmap File (o .: "ConwayGenesisFile") - <*> (fmap . fmap) GenesisHashConway (o .:? "ConwayGenesisHash") - <*> o .: "RequiresNetworkMagic" - <*> parseByronProtocolVersion o - <*> parseHardForkTriggers o - - parseByronProtocolVersion :: Object -> Parser Cardano.Chain.Update.ProtocolVersion - parseByronProtocolVersion o = - Cardano.Chain.Update.ProtocolVersion - <$> o .: "LastKnownBlockVersion-Major" - <*> o .: "LastKnownBlockVersion-Minor" - <*> o .: "LastKnownBlockVersion-Alt" - - parseHardForkTriggers :: Object -> Parser Consensus.CardanoHardForkTriggers - parseHardForkTriggers o = - Consensus.CardanoHardForkTriggers' - <$> parseShelleyHardForkEpoch o - <*> parseAllegraHardForkEpoch o - <*> parseMaryHardForkEpoch o - <*> parseAlonzoHardForkEpoch o - <*> parseBabbageHardForkEpoch o - <*> parseConwayHardForkEpoch o - <*> parseDijkstraHardForkEpoch o - parseShelleyHardForkEpoch :: Object -> Parser (Consensus.CardanoHardForkTrigger blk) - parseShelleyHardForkEpoch o = - asum - [ Consensus.CardanoTriggerHardForkAtEpoch <$> o .: "TestShelleyHardForkAtEpoch" - , pure Consensus.CardanoTriggerHardForkAtDefaultVersion - ] - - parseAllegraHardForkEpoch :: Object -> Parser (Consensus.CardanoHardForkTrigger blk) - parseAllegraHardForkEpoch o = - asum - [ Consensus.CardanoTriggerHardForkAtEpoch <$> o .: "TestAllegraHardForkAtEpoch" - , pure Consensus.CardanoTriggerHardForkAtDefaultVersion - ] - - parseMaryHardForkEpoch :: Object -> Parser (Consensus.CardanoHardForkTrigger blk) - parseMaryHardForkEpoch o = - asum - [ Consensus.CardanoTriggerHardForkAtEpoch <$> o .: "TestMaryHardForkAtEpoch" - , pure Consensus.CardanoTriggerHardForkAtDefaultVersion - ] - - parseAlonzoHardForkEpoch :: Object -> Parser (Consensus.CardanoHardForkTrigger blk) - parseAlonzoHardForkEpoch o = - asum - [ Consensus.CardanoTriggerHardForkAtEpoch <$> o .: "TestAlonzoHardForkAtEpoch" - , pure Consensus.CardanoTriggerHardForkAtDefaultVersion - ] - parseBabbageHardForkEpoch :: Object -> Parser (Consensus.CardanoHardForkTrigger blk) - parseBabbageHardForkEpoch o = - asum - [ Consensus.CardanoTriggerHardForkAtEpoch <$> o .: "TestBabbageHardForkAtEpoch" - , pure Consensus.CardanoTriggerHardForkAtDefaultVersion - ] - - parseConwayHardForkEpoch :: Object -> Parser (Consensus.CardanoHardForkTrigger blk) - parseConwayHardForkEpoch o = - asum - [ Consensus.CardanoTriggerHardForkAtEpoch <$> o .: "TestConwayHardForkAtEpoch" - , pure Consensus.CardanoTriggerHardForkAtDefaultVersion - ] - - parseDijkstraHardForkEpoch :: Object -> Parser (Consensus.CardanoHardForkTrigger blk) - parseDijkstraHardForkEpoch o = - asum - [ Consensus.CardanoTriggerHardForkAtEpoch <$> o .: "TestDijkstraHardForkAtEpoch" - , pure Consensus.CardanoTriggerHardForkAtDefaultVersion - ] - ----------------------------------------------------------------------- --- WARNING When adding new entries above, be aware that if there is an --- intra-era fork, then the numbering is not consecutive. ----------------------------------------------------------------------- +-- | The Byron PBFT signature threshold: always 'Nothing', so the consensus +-- default applies. A @cardano-config@ configuration has no such setting (reading +-- a flat configuration drops its @PBftSignatureThreshold@). It does not affect +-- reading or applying blocks. +ncPBftSignatureThreshold :: NodeConfig -> Maybe Double +ncPBftSignatureThreshold _ = Nothing +{-# DEPRECATED + ncPBftSignatureThreshold + "No longer read from the configuration: always Nothing, the consensus default" + #-} -parseNodeConfig :: ByteString -> Either Text NodeConfig -parseNodeConfig bs = - case Yaml.decodeEither' bs of - Left err -> Left $ "Error parsing node config: " <> textShow err - Right nc -> Right nc +-- | The Byron protocol version a node endorses: always 1.0.0. A +-- @cardano-config@ configuration has no such setting (reading a flat +-- configuration drops its @LastKnownBlockVersion-Major@, @-Minor@ and @-Alt@). +-- It does not affect reading or applying blocks. +ncByronProtocolVersion :: NodeConfig -> Cardano.Chain.Update.ProtocolVersion +ncByronProtocolVersion _ = fixedByronProtocolVersion +{-# DEPRECATED ncByronProtocolVersion "No longer read from the configuration: always 1.0.0" #-} + +-- | The Byron protocol version given to consensus, as a @cardano-config@ +-- configuration does not set one. +fixedByronProtocolVersion :: Cardano.Chain.Update.ProtocolVersion +fixedByronProtocolVersion = Cardano.Chain.Update.ProtocolVersion 1 0 0 + +-- | The Byron genesis file, relative to the directory of the configuration file +-- if the configuration names a relative path. +ncByronGenesisFile :: NodeConfig -> File ByronGenesisConfig 'In +ncByronGenesisFile = genesisFile (Cfg.byronGenesisFile . Cfg.byronGenesis) + +-- | The hash of the Byron genesis file, which 'readNodeConfig' has checked. +ncByronGenesisHash :: NodeConfig -> GenesisHashByron +ncByronGenesisHash = + GenesisHashByron + . Cardano.Crypto.Hash.Class.hashToTextAsHex + . Cfg.hash + . genesisReference (Cfg.byronGenesisFile . Cfg.byronGenesis) + +-- | The Shelley genesis file, relative to the directory of the configuration +-- file if the configuration names a relative path. +ncShelleyGenesisFile :: NodeConfig -> File ShelleyGenesisConfig 'In +ncShelleyGenesisFile = genesisFile Cfg.shelleyGenesis + +-- | The hash of the Shelley genesis file, which 'readNodeConfig' has checked. +ncShelleyGenesisHash :: NodeConfig -> GenesisHashShelley +ncShelleyGenesisHash = GenesisHashShelley . Cfg.hash . genesisReference Cfg.shelleyGenesis + +-- | The Alonzo genesis file, relative to the directory of the configuration file +-- if the configuration names a relative path. +ncAlonzoGenesisFile :: NodeConfig -> File AlonzoGenesis 'In +ncAlonzoGenesisFile = genesisFile Cfg.alonzoGenesis + +-- | The hash of the Alonzo genesis file, which 'readNodeConfig' has checked. +ncAlonzoGenesisHash :: NodeConfig -> GenesisHashAlonzo +ncAlonzoGenesisHash = GenesisHashAlonzo . Cfg.hash . genesisReference Cfg.alonzoGenesis + +-- | The Conway genesis file, relative to the directory of the configuration file +-- if the configuration names a relative path. +ncConwayGenesisFile :: NodeConfig -> File ConwayGenesisConfig 'In +ncConwayGenesisFile = genesisFile Cfg.conwayGenesis + +-- | The hash of the Conway genesis file, which 'readNodeConfig' has checked. +ncConwayGenesisHash :: NodeConfig -> GenesisHashConway +ncConwayGenesisHash = GenesisHashConway . Cfg.hash . genesisReference Cfg.conwayGenesis + +-- | Whether the Byron genesis requires the network magic in addresses and +-- transactions. A configuration that does not say requires none. +ncRequiresNetworkMagic :: NodeConfig -> Cardano.Crypto.RequiresNetworkMagic +ncRequiresNetworkMagic enc = + case Ledger.fromSMaybe Cfg.RequiresNoMagic + . Cfg.byronReqNetworkMagic + . Cfg.byronGenesis + . Cfg.protocolConfiguration + $ ncConfiguration enc of + Cfg.RequiresMagic -> Cardano.Crypto.RequiresMagic + Cfg.RequiresNoMagic -> Cardano.Crypto.RequiresNoMagic + +-- | The hard fork triggers of the configuration's @Testing@ section. +ncHardForkTriggers :: NodeConfig -> Consensus.CardanoHardForkTriggers +ncHardForkTriggers = hardForkTriggers . Cfg.testingConfiguration . ncConfiguration + +-- | A genesis file reference of the configuration: the path and its hash. +genesisReference + :: (Cfg.ProtocolConfiguration Identity -> Cfg.Hashed FilePath) + -> NodeConfig + -> Cfg.Hashed FilePath +genesisReference ref = ref . Cfg.protocolConfiguration . ncConfiguration + +-- | A genesis file of the configuration, relative to the directory of the +-- configuration file if the configuration names a relative path. +genesisFile + :: (Cfg.ProtocolConfiguration Identity -> Cfg.Hashed FilePath) + -> NodeConfig + -> File content 'In +genesisFile ref enc = + File . mkAdjustPath (Cfg.configFilePath (ncConfiguration enc)) . Cfg.hashed $ + genesisReference ref enc mkAdjustPath :: FilePath -> (FilePath -> FilePath) mkAdjustPath nodeConfigFilePath fp = takeDirectory nodeConfigFilePath fp -readByteString - :: MonadError Text m - => MonadIO m - => FilePath - -> Text - -> m ByteString -readByteString fp cfgType = (liftEither <=< liftIO) $ - catch (Right <$> BS.readFile fp) $ \(_ :: IOException) -> - return $ - Left $ - mconcat - ["Cannot read the ", cfgType, " configuration file at : ", Text.pack fp] - initLedgerStateVar :: SomeHasFS IO -> GenesisConfig -> IO LedgerState initLedgerStateVar fs genesisConfig = do (pinfo, _) <- mkProtocolInfoCardano fs genesisConfig @@ -1501,9 +1549,10 @@ mkProtocolInfoCardano fs (GenesisCardano dnc byronGenesis shelleyGenesisHash tra { Consensus.byronProtocolParams = Consensus.ProtocolParamsByron { Consensus.byronGenesis = byronGenesis - , Consensus.byronPbftSignatureThreshold = - Consensus.PBftSignatureThreshold <$> ncPBftSignatureThreshold dnc - , Consensus.byronProtocolVersion = ncByronProtocolVersion dnc + , -- Neither is set by a cardano-config configuration (see + -- 'ncPBftSignatureThreshold' and 'ncByronProtocolVersion'). + Consensus.byronPbftSignatureThreshold = Nothing + , Consensus.byronProtocolVersion = fixedByronProtocolVersion , Consensus.byronSoftwareVersion = Byron.softwareVersion , Consensus.byronLeaderCredentials = Nothing } @@ -1529,13 +1578,17 @@ readCardanoGenesisConfig => NodeConfig -> t m GenesisConfig readCardanoGenesisConfig enc = do - byronGenesis <- readByronGenesisConfig enc - ShelleyConfig shelleyGenesis shelleyGenesisHash <- readShelleyGenesisConfig enc - alonzoGenesis <- readAlonzoGenesisConfig enc - conwayGenesis <- readConwayGenesisConfig enc - -- TODO Dijkstra: build real genesis value - let dijkstraGenesis = exampleDijkstraGenesis -- TODO Dijkstra: add plumbing to read genesis - let transCfg = Ledger.mkLatestTransitionConfig shelleyGenesis alonzoGenesis conwayGenesis dijkstraGenesis + let byronGenesis = readByronGenesisConfig enc + ShelleyConfig shelleyGenesis shelleyGenesisHash = readShelleyGenesisConfig enc + alonzoGenesis = readAlonzoGenesisConfig enc + conwayGenesis = readConwayGenesisConfig enc + -- The ledger always needs a Dijkstra genesis, even when Dijkstra is not + -- used, but cardano-config only reads one when + -- @ExperimentalHardForksEnabled@ is true. Otherwise this placeholder fills + -- the slot, and 'hardForkTriggers' ignores the Dijkstra epoch. + dijkstraGenesis = + Ledger.fromSMaybe exampleDijkstraGenesis . Cfg.experimentalGenesisConfig $ ncConfiguration enc + transCfg = Ledger.mkLatestTransitionConfig shelleyGenesis alonzoGenesis conwayGenesis dijkstraGenesis pure $ GenesisCardano enc byronGenesis shelleyGenesisHash transCfg -- | Resolve a Shelley genesis' 'Ledger.sgInitialFunds' against its @@ -1617,48 +1670,14 @@ exampleDijkstraGenesis = } } -data GenesisConfigError - = NEError !Text - | NEByronConfig !FilePath !Cardano.Chain.Genesis.ConfigurationError - | NEShelleyConfig !FilePath !Text - | NEAlonzoConfig !FilePath !Text - | NEConwayConfig !FilePath !Text - | NECardanoConfig !Text +newtype GenesisConfigError + = NECardanoConfig Text deriving Show instance Exception GenesisConfigError instance Error GenesisConfigError where prettyError = \case - NEError t -> "Error:" <+> pretty t - NEByronConfig fp ce -> - mconcat - [ "Failed reading Byron genesis file " - , pretty fp - , ": " - , pshow ce - ] - NEShelleyConfig fp txt -> - mconcat - [ "Failed reading Shelley genesis file " - , pretty fp - , ": " - , pretty txt - ] - NEAlonzoConfig fp txt -> - mconcat - [ "Failed reading Alonzo genesis file " - , pretty fp - , ": " - , pretty txt - ] - NEConwayConfig fp txt -> - mconcat - [ "Failed reading Conway genesis file " - , pretty fp - , ": " - , pretty txt - ] NECardanoConfig err -> mconcat [ "With Cardano protocol, Byron/Shelley config mismatch:\n" @@ -1666,56 +1685,26 @@ instance Error GenesisConfigError where , pretty err ] -readByronGenesisConfig - :: MonadIOTransError GenesisConfigError t m - => NodeConfig - -> t m Cardano.Chain.Genesis.Config -readByronGenesisConfig enc = do - let file = unFile $ ncByronGenesisFile enc - (_, actualHash) <- - modifyError (NEByronConfig file . Cardano.Chain.Genesis.ConfigurationGenesisDataError) $ - Cardano.Chain.Genesis.readGenesisData file - mExpectedHash <- forM (ncByronGenesisHash enc) $ \expectedHash -> - liftEither - . first NEError - $ Cardano.Crypto.Hashing.decodeAbstractHash (unGenesisHashByron expectedHash) - -- do the hash check only if the hash is present in the configuration file - -- otherwise `genesisHash` will always contain the actual hash - let genesisHash = - fromMaybe (Cardano.Chain.Genesis.unGenesisHash actualHash) mExpectedHash - modifyError (NEByronConfig file) $ - -- note that mkConfigFromFile decodes genesis and recomputes the hash again - -- The genesis hash check there is mandatory, so we have to provide an actual hash of the genesis if there was not - -- any in the node configuration. - Cardano.Chain.Genesis.mkConfigFromFile (ncRequiresNetworkMagic enc) file genesisHash - -readShelleyGenesisConfig - :: MonadIOTransError GenesisConfigError t m - => NodeConfig - -> t m ShelleyConfig -readShelleyGenesisConfig enc = do - let file = ncShelleyGenesisFile enc - modifyError (NEShelleyConfig (unFile file) . renderShelleyGenesisError) $ - readShelleyGenesis file (ncShelleyGenesisHash enc) +-- | The Byron genesis of a node configuration, which 'readNodeConfig' has read +-- and checked against its hash. +readByronGenesisConfig :: NodeConfig -> Cardano.Chain.Genesis.Config +readByronGenesisConfig = Cfg.byronGenesisConfig . ncConfiguration -readAlonzoGenesisConfig - :: MonadIOTransError GenesisConfigError t m - => NodeConfig - -> t m AlonzoGenesis -readAlonzoGenesisConfig enc = do - let file = ncAlonzoGenesisFile enc - modifyError (NEAlonzoConfig (unFile file) . renderAlonzoGenesisError) $ - readAlonzoGenesis file (ncAlonzoGenesisHash enc) - --- | If the conway genesis file does not exist we simply put in a default. -readConwayGenesisConfig - :: MonadIOTransError GenesisConfigError t m - => NodeConfig - -> t m ConwayGenesis -readConwayGenesisConfig enc = do - let fp = ncConwayGenesisFile enc - modifyError (NEConwayConfig (unFile fp) . renderConwayGenesisError) $ - readConwayGenesis fp (ncConwayGenesisHash enc) +-- | The Shelley genesis of a node configuration, and its hash, which +-- 'readNodeConfig' has read and checked. +readShelleyGenesisConfig :: NodeConfig -> ShelleyConfig +readShelleyGenesisConfig enc = + ShelleyConfig (Cfg.shelleyGenesisConfig $ ncConfiguration enc) (ncShelleyGenesisHash enc) + +-- | The Alonzo genesis of a node configuration, which 'readNodeConfig' has read +-- and checked against its hash. +readAlonzoGenesisConfig :: NodeConfig -> AlonzoGenesis +readAlonzoGenesisConfig = Cfg.alonzoGenesisConfig . ncConfiguration + +-- | The Conway genesis of a node configuration, which 'readNodeConfig' has read +-- and checked against its hash. +readConwayGenesisConfig :: NodeConfig -> ConwayGenesis +readConwayGenesisConfig = Cfg.conwayGenesisConfig . ncConfiguration readShelleyGenesis :: forall m t @@ -1774,117 +1763,6 @@ renderShelleyGenesisError sge = , err ] -readAlonzoGenesis - :: forall m t - . MonadIOTransError AlonzoGenesisError t m - => File AlonzoGenesis 'In - -> Maybe GenesisHashAlonzo - -> t m AlonzoGenesis -readAlonzoGenesis (File file) mExpectedGenesisHash = do - content <- - modifyError id $ handleIOExceptT (AlonzoGenesisReadError file . textShow) $ LBS.readFile file - let genesisHash = GenesisHashAlonzo . Cardano.Crypto.Hash.Class.hashWith id $ LBS.toStrict content - checkExpectedGenesisHash genesisHash - modifyError (AlonzoGenesisDecodeError file . Text.pack) . liftEither $ - A.eitherDecode content - where - checkExpectedGenesisHash :: GenesisHashAlonzo -> t m () - checkExpectedGenesisHash actual = forM_ mExpectedGenesisHash $ \expectedGenesisHash -> - when (actual /= expectedGenesisHash) $ - throwError (AlonzoGenesisHashMismatch actual expectedGenesisHash) - -data AlonzoGenesisError - = AlonzoGenesisReadError !FilePath !Text - | AlonzoGenesisHashMismatch !GenesisHashAlonzo !GenesisHashAlonzo -- actual, expected - | AlonzoGenesisDecodeError !FilePath !Text - deriving Show - -instance Exception AlonzoGenesisError - -renderAlonzoGenesisError :: AlonzoGenesisError -> Text -renderAlonzoGenesisError sge = - case sge of - AlonzoGenesisReadError fp err -> - mconcat - [ "There was an error reading the genesis file: " - , Text.pack fp - , " Error: " - , err - ] - AlonzoGenesisHashMismatch actual expected -> - mconcat - [ "Wrong Alonzo genesis file: the actual hash is " - , renderHash (unGenesisHashAlonzo actual) - , ", but the expected Alonzo genesis hash given in the node " - , "configuration file is " - , renderHash (unGenesisHashAlonzo expected) - , "." - ] - AlonzoGenesisDecodeError fp err -> - mconcat - [ "There was an error parsing the genesis file: " - , Text.pack fp - , " Error: " - , err - ] - -readConwayGenesis - :: forall m t - . MonadIOTransError ConwayGenesisError t m - => ConwayGenesisFile 'In - -> Maybe GenesisHashConway - -> t m ConwayGenesis -readConwayGenesis (File file) mExpectedGenesisHash = do - content <- - modifyError id $ handleIOExceptT (ConwayGenesisReadError file . textShow) $ BS.readFile file - let genesisHash = GenesisHashConway (Cardano.Crypto.Hash.Class.hashWith id content) - checkExpectedGenesisHash genesisHash - liftEither . first (ConwayGenesisDecodeError file . Text.pack) $ Aeson.eitherDecodeStrict' content - where - checkExpectedGenesisHash :: GenesisHashConway -> t m () - checkExpectedGenesisHash actual = forM_ mExpectedGenesisHash $ \expectedGenesisHash -> - when (actual /= expectedGenesisHash) $ - throwError (ConwayGenesisHashMismatch actual expectedGenesisHash) - -data ConwayGenesisError - = ConwayGenesisReadError !FilePath !Text - | ConwayGenesisHashMismatch !GenesisHashConway !GenesisHashConway -- actual, expected - | ConwayGenesisFileMissing - | ConwayGenesisDecodeError !FilePath !Text - deriving Show - -instance Exception ConwayGenesisError - -renderConwayGenesisError :: ConwayGenesisError -> Text -renderConwayGenesisError = \case - ConwayGenesisFileMissing -> - mconcat - [ "\"ConwayGenesisFile\" is missing from node configuration. " - ] - ConwayGenesisReadError fp err -> - mconcat - [ "There was an error reading the genesis file: " - , Text.pack fp - , " Error: " - , err - ] - ConwayGenesisHashMismatch actual expected -> - mconcat - [ "Wrong Conway genesis file: the actual hash is " - , renderHash (unGenesisHashConway actual) - , ", but the expected Conway genesis hash given in the node " - , "configuration file is " - , renderHash (unGenesisHashConway expected) - , "." - ] - ConwayGenesisDecodeError fp err -> - mconcat - [ "There was an error parsing the genesis file: " - , Text.pack fp - , " Error: " - , err - ] - renderHash :: Cardano.Crypto.Hash.Class.Hash Cardano.Crypto.Hash.Blake2b.Blake2b_256 ByteString -> Text renderHash h = Text.decodeUtf8 $ Base16.encode (Cardano.Crypto.Hash.Class.hashToBytes h) diff --git a/cardano-api/test/cardano-api-test/Test/Cardano/Api/NodeConfig.hs b/cardano-api/test/cardano-api-test/Test/Cardano/Api/NodeConfig.hs index 3f63a1adac..4010a48381 100644 --- a/cardano-api/test/cardano-api-test/Test/Cardano/Api/NodeConfig.hs +++ b/cardano-api/test/cardano-api-test/Test/Cardano/Api/NodeConfig.hs @@ -1,69 +1,331 @@ +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} +{-# OPTIONS_GHC -Wno-deprecations #-} module Test.Cardano.Api.NodeConfig ( tests ) where -import Cardano.Api (EpochNo (..)) -import Cardano.Api.LedgerState (NodeConfig (..)) +import Cardano.Api (EpochNo (..), File (..)) +import Cardano.Api.LedgerState + ( GenesisConfig (..) + , NodeConfig + , NodeConfigError (..) + , ShelleyConfig (..) + , envSecurityParam + , initialLedgerState + , ncByronProtocolVersion + , ncHardForkTriggers + , ncPBftSignatureThreshold + , readAlonzoGenesisConfig + , readByronGenesisConfig + , readCardanoGenesisConfig + , readConwayGenesisConfig + , readNodeConfig + , readShelleyGenesisConfig + ) +import Cardano.Chain.Genesis qualified as Byron +import Cardano.Chain.Update qualified as Byron +import Cardano.Configuration qualified as Cfg +import Cardano.Ledger.Alonzo.Genesis qualified as Alonzo +import Cardano.Ledger.Api.Transition qualified as Ledger +import Cardano.Ledger.BaseTypes qualified as Ledger +import Cardano.Ledger.Conway.Genesis qualified as Conway +import Cardano.Ledger.Conway.PParams qualified as Conway +import Cardano.Ledger.Dijkstra.Genesis qualified as Dijkstra +import Cardano.Ledger.Dijkstra.PParams qualified as Dijkstra +import Cardano.Ledger.Shelley.Genesis qualified as Shelley import Ouroboros.Consensus.Cardano.Node qualified as Consensus +import Control.Monad.Except (runExceptT) import Data.Aeson qualified as Aeson +import Data.Maybe.Strict (StrictMaybe (..)) +import Data.Text (Text) +import Data.Text qualified as Text +import Data.Time.Clock.POSIX (posixSecondsToUTCTime) +import Data.Word (Word32) import GHC.Stack +import Lens.Micro ((^.)) +import System.Directory (makeAbsolute) +import System.FS.API (SomeHasFS (..)) +import System.FS.API.Types (MountPoint (..)) +import System.FS.IO (ioHasFS) +import System.FilePath (takeDirectory, takeFileName, ()) import Hedgehog as H -import Hedgehog.Extras (propertyOnce) +import Hedgehog.Extras qualified as H import Test.Tasty (TestTree, testGroup) import Test.Tasty.Hedgehog (testProperty) --- | A minimal node configuration with the given extra keys. -nodeConfigWith :: [(Aeson.Key, Aeson.Value)] -> Aeson.Value -nodeConfigWith extras = - Aeson.object $ - [ "ByronGenesisFile" Aeson..= ("byron-genesis.json" :: String) - , "ShelleyGenesisFile" Aeson..= ("shelley-genesis.json" :: String) - , "AlonzoGenesisFile" Aeson..= ("alonzo-genesis.json" :: String) - , "ConwayGenesisFile" Aeson..= ("conway-genesis.json" :: String) - , "RequiresNetworkMagic" Aeson..= ("RequiresNoMagic" :: String) - , "LastKnownBlockVersion-Major" Aeson..= (3 :: Int) - , "LastKnownBlockVersion-Minor" Aeson..= (0 :: Int) - , "LastKnownBlockVersion-Alt" Aeson..= (0 :: Int) - ] - <> map (uncurry (Aeson..=)) extras - -parseTriggers - :: (HasCallStack, MonadTest m) - => [(Aeson.Key, Aeson.Value)] - -> m Consensus.CardanoHardForkTriggers -parseTriggers extras = - case Aeson.fromJSON $ nodeConfigWith extras of - Aeson.Error e -> withFrozenCallStack $ H.annotate e >> H.failure - Aeson.Success nc -> pure $ ncHardForkTriggers nc - -prop_parse_dijkstra_hard_fork_at_epoch :: Property -prop_parse_dijkstra_hard_fork_at_epoch = propertyOnce $ do - triggers <- parseTriggers [("TestDijkstraHardForkAtEpoch", Aeson.toJSON (5 :: Int))] - case triggers of +-- | The genesis files the configurations below name. +genesisDir :: FilePath +genesisDir = "test/cardano-api-test/files/input/node-config" + +-- | The genesis keys of a configuration naming the files in 'genesisDir' by +-- absolute path, with their hashes. +genesisKeys :: FilePath -> [(Aeson.Key, Aeson.Value)] +genesisKeys dir = + [ "ByronGenesisFile" Aeson..= (dir "byron-genesis.json") + , "ByronGenesisHash" + Aeson..= ("31cac3a016a7d1db5460ad98e43c27eee4bad769c739a694eddd6a82d944130a" :: Text) + , "ShelleyGenesisFile" Aeson..= (dir "shelley-genesis.json") + , "ShelleyGenesisHash" + Aeson..= ("6dc7b632017152c61a69dd17f50c03bfabbe3d24a9ad27273693bb8666140423" :: Text) + , "AlonzoGenesisFile" Aeson..= (dir "alonzo-genesis.json") + , "AlonzoGenesisHash" + Aeson..= ("7e94a15f55d1e82d10f09203fa1d40f8eede58fd8066542cf6566008068ed874" :: Text) + , "ConwayGenesisFile" Aeson..= (dir "conway-genesis.json") + , "ConwayGenesisHash" + Aeson..= ("15a199f895e461ec0ffc6dd4e4028af28a492ab4e806d39cb674c88f7643ef62" :: Text) + , "RequiresNetworkMagic" Aeson..= ("RequiresNoMagic" :: Text) + ] + +-- | The keys naming the Dijkstra genesis in 'genesisDir', with experimental hard +-- forks enabled or not. That genesis is the example Dijkstra genesis, except for +-- its maximum reference script size per transaction: 307200 instead of 204800. +dijkstraKeys :: Bool -> FilePath -> [(Aeson.Key, Aeson.Value)] +dijkstraKeys enabled dir = + [ "ExperimentalHardForksEnabled" Aeson..= enabled + , "DijkstraGenesisFile" Aeson..= (dir "dijkstra-genesis.json") + , "DijkstraGenesisHash" + Aeson..= ("6569e322c881684123b5f962176afb8d99d664123b066d24e7d32ad651dc0f95" :: Text) + ] + +-- | Write the configuration to a file in a fresh workspace, and use the file. +withConfigFile + :: HasCallStack + => (FilePath -> Aeson.Value) + -- ^ The configuration, given the absolute path of 'genesisDir'. + -> (FilePath -> H.Integration ()) + -> H.Integration () +withConfigFile mkConfig use = withFrozenCallStack $ do + dir <- H.evalIO $ makeAbsolute genesisDir + H.moduleWorkspace "node-config" $ \ws -> do + let file = ws "config.json" + H.evalIO . Aeson.encodeFile file $ mkConfig dir + use file + +-- | Write the configuration to a file in a fresh workspace, read it back with +-- 'readNodeConfig', and check the result. +withConfig + :: HasCallStack + => (FilePath -> Aeson.Value) + -- ^ The configuration, given the absolute path of 'genesisDir'. + -> (Either NodeConfigError NodeConfig -> H.Integration ()) + -> H.Integration () +withConfig mkConfig expect = withFrozenCallStack $ withConfigFile mkConfig $ \file -> + H.evalIO (runExceptT . fmap fst . readNodeConfig $ File file) >>= expect + +-- | A configuration in the flat format, with the given extra keys. +flatConfig :: [(Aeson.Key, Aeson.Value)] -> FilePath -> Aeson.Value +flatConfig extra dir = Aeson.object $ genesisKeys dir <> extra + +-- | The configuration reads, and its Dijkstra hard fork is at epoch 5. +expectDijkstraAtEpoch5 :: HasCallStack => Either NodeConfigError NodeConfig -> H.Integration () +expectDijkstraAtEpoch5 result = withFrozenCallStack $ do + nc <- H.evalEither result + case ncHardForkTriggers nc of Consensus.CardanoHardForkTriggers'{Consensus.triggerHardForkDijkstra = trigger} -> case trigger of Consensus.CardanoTriggerHardForkAtEpoch (EpochNo 5) -> H.success other -> H.annotateShow other >> H.failure -prop_parse_dijkstra_hard_fork_default :: Property -prop_parse_dijkstra_hard_fork_default = propertyOnce $ do - triggers <- parseTriggers [] - case triggers of +-- | The configuration reads, and its Dijkstra hard fork is at the default +-- protocol version. +expectDijkstraAtDefaultVersion + :: HasCallStack => Either NodeConfigError NodeConfig -> H.Integration () +expectDijkstraAtDefaultVersion result = withFrozenCallStack $ do + nc <- H.evalEither result + case ncHardForkTriggers nc of Consensus.CardanoHardForkTriggers'{Consensus.triggerHardForkDijkstra = trigger} -> case trigger of Consensus.CardanoTriggerHardForkAtDefaultVersion -> H.success other -> H.annotateShow other >> H.failure +-- | The maximum reference script size per transaction of the Dijkstra genesis +-- that 'readCardanoGenesisConfig' gives for the configuration. +readMaxRefScriptSizePerTx :: HasCallStack => NodeConfig -> H.Integration Word32 +readMaxRefScriptSizePerTx nc = withFrozenCallStack $ do + GenesisCardano _ _ _ transCfg <- + H.evalEither =<< H.evalIO (runExceptT $ readCardanoGenesisConfig nc) + pure . Dijkstra.udppMaxRefScriptSizePerTx . Dijkstra.dgUpgradePParams $ + transCfg ^. Ledger.tcTranslationContextL + +-- | The configuration does not read: cardano-config rejects it with an error +-- that passes the given check. +expectRejectedWith + :: HasCallStack + => (Cfg.ConfigurationParsingError -> H.Integration ()) + -> Either NodeConfigError NodeConfig + -> H.Integration () +expectRejectedWith checkError result = withFrozenCallStack $ + case result of + Right _ -> H.annotate "the configuration was read" >> H.failure + Left (NodeConfigParsingError err) -> H.annotateShow err >> checkError err + Left err -> H.annotateShow err >> H.failure + +prop_read_dijkstra_hard_fork_at_epoch :: Property +prop_read_dijkstra_hard_fork_at_epoch = H.propertyOnce $ withConfig config expectDijkstraAtEpoch5 + where + config dir = + flatConfig (dijkstraKeys True dir <> ["TestDijkstraHardForkAtEpoch" Aeson..= (5 :: Int)]) dir + +prop_ignore_dijkstra_hard_fork_without_experimental_hard_forks :: Property +prop_ignore_dijkstra_hard_fork_without_experimental_hard_forks = + H.propertyOnce $ + withConfig + (flatConfig ["TestDijkstraHardForkAtEpoch" Aeson..= (5 :: Int)]) + expectDijkstraAtDefaultVersion + +prop_read_dijkstra_hard_fork_default :: Property +prop_read_dijkstra_hard_fork_default = + H.propertyOnce $ withConfig (flatConfig []) expectDijkstraAtDefaultVersion + +prop_read_enveloped_config :: Property +prop_read_enveloped_config = H.propertyOnce $ withConfig envelopedConfig expectDijkstraAtEpoch5 + where + envelopedConfig dir = + Aeson.object + [ "Version" Aeson..= (2 :: Int) + , "Configuration" + Aeson..= Aeson.object + [ "Protocol" Aeson..= Aeson.object (genesisKeys dir) + , "Testing" + Aeson..= Aeson.object + (dijkstraKeys True dir <> ["TestDijkstraHardForkAtEpoch" Aeson..= (5 :: Int)]) + ] + ] + +prop_reject_config_without_genesis_hashes :: Property +prop_reject_config_without_genesis_hashes = + H.propertyOnce . withConfig withoutHashes . expectRejectedWith $ \err -> do + -- The protocol section of the configuration itself, not a genesis file. + Cfg.errFile err H.=== SNothing + Cfg.errSection err H.=== SJust "Protocol" + where + withoutHashes dir = + Aeson.object + [ (k, v) + | (k, v) <- genesisKeys dir + , k `notElem` ["ByronGenesisHash", "ShelleyGenesisHash", "AlonzoGenesisHash", "ConwayGenesisHash"] + ] + +-- | A configuration whose hash for one genesis file is wrong is rejected, and the +-- error names that file. The Byron hash is checked differently from the others +-- (over canonical JSON rather than the raw bytes). +prop_reject_wrong_genesis_hash + :: Aeson.Key + -- ^ The hash to break. + -> FilePath + -- ^ The genesis file it is the hash of. + -> Property +prop_reject_wrong_genesis_hash hashKey genesisFile = + H.propertyOnce . withConfig wrongHash . expectRejectedWith $ \err -> + (takeFileName <$> Cfg.errFile err) H.=== SJust genesisFile + where + wrongHash dir = + Aeson.object + [ if k == hashKey then (k, Aeson.toJSON (Text.replicate 64 "0")) else (k, v) + | (k, v) <- genesisKeys dir + ] + +prop_reject_missing_genesis_file :: Property +prop_reject_missing_genesis_file = + H.propertyOnce . withConfig missingShelleyGenesis . expectRejectedWith $ \err -> + (takeFileName <$> Cfg.errFile err) H.=== SJust "missing-genesis.json" + where + missingShelleyGenesis dir = + Aeson.object + [ if k == "ShelleyGenesisFile" then (k, Aeson.toJSON (dir "missing-genesis.json")) else (k, v) + | (k, v) <- genesisKeys dir + ] + +-- | Each genesis file ends up in the configuration. The values are the ones in +-- the files in 'genesisDir'. +prop_read_genesis_files :: Property +prop_read_genesis_files = H.propertyOnce . withConfig (flatConfig []) $ \result -> do + nc <- H.evalEither result + Byron.gdStartTime (Byron.configGenesisData $ readByronGenesisConfig nc) + H.=== posixSecondsToUTCTime 1506203091 + Shelley.sgNetworkMagic (scConfig $ readShelleyGenesisConfig nc) H.=== 764824073 + Alonzo.agCollateralPercentage (readAlonzoGenesisConfig nc) H.=== 150 + Conway.ucppGovActionLifetime (Conway.cgUpgradePParams $ readConwayGenesisConfig nc) + H.=== Ledger.EpochInterval 6 + +-- | The Byron settings that are no longer read. Both functions are deprecated, +-- hence @-Wno-deprecations@ in this module. +prop_byron_constants :: Property +prop_byron_constants = H.propertyOnce . withConfig (flatConfig []) $ \result -> do + nc <- H.evalEither result + ncPBftSignatureThreshold nc H.=== Nothing + ncByronProtocolVersion nc H.=== Byron.ProtocolVersion 1 0 0 + +prop_initial_ledger_state :: Property +prop_initial_ledger_state = H.propertyOnce . withConfigFile (flatConfig []) $ \file -> do + let fs = SomeHasFS . ioHasFS . MountPoint $ takeDirectory file + (env, _) <- H.evalEither =<< H.evalIO (runExceptT $ initialLedgerState fs (File file)) + -- The security parameter of the genesis files in 'genesisDir'. + envSecurityParam env H.=== 2160 + +prop_read_dijkstra_genesis_with_experimental_hard_forks :: Property +prop_read_dijkstra_genesis_with_experimental_hard_forks = + H.propertyOnce . withConfig (\dir -> flatConfig (dijkstraKeys True dir) dir) $ \result -> do + nc <- H.evalEither result + size <- readMaxRefScriptSizePerTx nc + size H.=== 307200 + +prop_use_example_dijkstra_genesis_without_experimental_hard_forks :: Property +prop_use_example_dijkstra_genesis_without_experimental_hard_forks = + H.propertyOnce . withConfig (\dir -> flatConfig (dijkstraKeys False dir) dir) $ \result -> do + nc <- H.evalEither result + size <- readMaxRefScriptSizePerTx nc + -- The example Dijkstra genesis's, not the one in the file the configuration + -- names. + size H.=== 204800 + +prop_reject_experimental_hard_forks_without_dijkstra_genesis :: Property +prop_reject_experimental_hard_forks_without_dijkstra_genesis = + H.propertyOnce . withConfig (flatConfig ["ExperimentalHardForksEnabled" Aeson..= True]) $ \case + Left (NodeConfigResolutionError (Cfg.ViolatedChecks _)) -> H.success + Left err -> H.annotateShow err >> H.failure + Right _ -> H.annotate "the configuration was read" >> H.failure + tests :: TestTree tests = testGroup "Test.Cardano.Api.NodeConfig" - [ testProperty "parse TestDijkstraHardForkAtEpoch" prop_parse_dijkstra_hard_fork_at_epoch - , testProperty "parse Dijkstra hard fork default" prop_parse_dijkstra_hard_fork_default + [ testProperty + "read TestDijkstraHardForkAtEpoch with experimental hard forks" + prop_read_dijkstra_hard_fork_at_epoch + , testProperty + "ignore TestDijkstraHardForkAtEpoch without experimental hard forks" + prop_ignore_dijkstra_hard_fork_without_experimental_hard_forks + , testProperty "read Dijkstra hard fork default" prop_read_dijkstra_hard_fork_default + , testProperty "read an enveloped configuration" prop_read_enveloped_config + , testProperty + "reject a configuration without genesis hashes" + prop_reject_config_without_genesis_hashes + , testProperty "reject a wrong Byron genesis hash" $ + prop_reject_wrong_genesis_hash "ByronGenesisHash" "byron-genesis.json" + , testProperty "reject a wrong Shelley genesis hash" $ + prop_reject_wrong_genesis_hash "ShelleyGenesisHash" "shelley-genesis.json" + , testProperty "reject a wrong Alonzo genesis hash" $ + prop_reject_wrong_genesis_hash "AlonzoGenesisHash" "alonzo-genesis.json" + , testProperty "reject a wrong Conway genesis hash" $ + prop_reject_wrong_genesis_hash "ConwayGenesisHash" "conway-genesis.json" + , testProperty "reject a missing genesis file" prop_reject_missing_genesis_file + , testProperty "read the genesis files" prop_read_genesis_files + , testProperty "read the Byron constants" prop_byron_constants + , testProperty "read an initial ledger state" prop_initial_ledger_state + , testProperty + "read the Dijkstra genesis with experimental hard forks" + prop_read_dijkstra_genesis_with_experimental_hard_forks + , testProperty + "use the example Dijkstra genesis without experimental hard forks" + prop_use_example_dijkstra_genesis_without_experimental_hard_forks + , testProperty + "reject experimental hard forks without a Dijkstra genesis" + prop_reject_experimental_hard_forks_without_dijkstra_genesis ] diff --git a/cardano-api/test/cardano-api-test/files/input/node-config/alonzo-genesis.json b/cardano-api/test/cardano-api-test/files/input/node-config/alonzo-genesis.json new file mode 100644 index 0000000000..0fd90deeb7 --- /dev/null +++ b/cardano-api/test/cardano-api-test/files/input/node-config/alonzo-genesis.json @@ -0,0 +1,196 @@ +{ + "lovelacePerUTxOWord": 34482, + "executionPrices": { + "prSteps": + { + "numerator" : 721, + "denominator" : 10000000 + }, + "prMem": + { + "numerator" : 577, + "denominator" : 10000 + } + }, + "maxTxExUnits": { + "exUnitsMem": 10000000, + "exUnitsSteps": 10000000000 + }, + "maxBlockExUnits": { + "exUnitsMem": 50000000, + "exUnitsSteps": 40000000000 + }, + "maxValueSize": 5000, + "collateralPercentage": 150, + "maxCollateralInputs": 3, + "costModels": { + "PlutusV1": { + "sha2_256-memory-arguments": 4, + "equalsString-cpu-arguments-constant": 1000, + "cekDelayCost-exBudgetMemory": 100, + "lessThanEqualsByteString-cpu-arguments-intercept": 103599, + "divideInteger-memory-arguments-minimum": 1, + "appendByteString-cpu-arguments-slope": 621, + "blake2b-cpu-arguments-slope": 29175, + "iData-cpu-arguments": 150000, + "encodeUtf8-cpu-arguments-slope": 1000, + "unBData-cpu-arguments": 150000, + "multiplyInteger-cpu-arguments-intercept": 61516, + "cekConstCost-exBudgetMemory": 100, + "nullList-cpu-arguments": 150000, + "equalsString-cpu-arguments-intercept": 150000, + "trace-cpu-arguments": 150000, + "mkNilData-memory-arguments": 32, + "lengthOfByteString-cpu-arguments": 150000, + "cekBuiltinCost-exBudgetCPU": 29773, + "bData-cpu-arguments": 150000, + "subtractInteger-cpu-arguments-slope": 0, + "unIData-cpu-arguments": 150000, + "consByteString-memory-arguments-intercept": 0, + "divideInteger-memory-arguments-slope": 1, + "divideInteger-cpu-arguments-model-arguments-slope": 118, + "listData-cpu-arguments": 150000, + "headList-cpu-arguments": 150000, + "chooseData-memory-arguments": 32, + "equalsInteger-cpu-arguments-intercept": 136542, + "sha3_256-cpu-arguments-slope": 82363, + "sliceByteString-cpu-arguments-slope": 5000, + "unMapData-cpu-arguments": 150000, + "lessThanInteger-cpu-arguments-intercept": 179690, + "mkCons-cpu-arguments": 150000, + "appendString-memory-arguments-intercept": 0, + "modInteger-cpu-arguments-model-arguments-slope": 118, + "ifThenElse-cpu-arguments": 1, + "mkNilPairData-cpu-arguments": 150000, + "lessThanEqualsInteger-cpu-arguments-intercept": 145276, + "addInteger-memory-arguments-slope": 1, + "chooseList-memory-arguments": 32, + "constrData-memory-arguments": 32, + "decodeUtf8-cpu-arguments-intercept": 150000, + "equalsData-memory-arguments": 1, + "subtractInteger-memory-arguments-slope": 1, + "appendByteString-memory-arguments-intercept": 0, + "lengthOfByteString-memory-arguments": 4, + "headList-memory-arguments": 32, + "listData-memory-arguments": 32, + "consByteString-cpu-arguments-intercept": 150000, + "unIData-memory-arguments": 32, + "remainderInteger-memory-arguments-minimum": 1, + "bData-memory-arguments": 32, + "lessThanByteString-cpu-arguments-slope": 248, + "encodeUtf8-memory-arguments-intercept": 0, + "cekStartupCost-exBudgetCPU": 100, + "multiplyInteger-memory-arguments-intercept": 0, + "unListData-memory-arguments": 32, + "remainderInteger-cpu-arguments-model-arguments-slope": 118, + "cekVarCost-exBudgetCPU": 29773, + "remainderInteger-memory-arguments-slope": 1, + "cekForceCost-exBudgetCPU": 29773, + "sha2_256-cpu-arguments-slope": 29175, + "equalsInteger-memory-arguments": 1, + "indexByteString-memory-arguments": 1, + "addInteger-memory-arguments-intercept": 1, + "chooseUnit-cpu-arguments": 150000, + "sndPair-cpu-arguments": 150000, + "cekLamCost-exBudgetCPU": 29773, + "fstPair-cpu-arguments": 150000, + "quotientInteger-memory-arguments-minimum": 1, + "decodeUtf8-cpu-arguments-slope": 1000, + "lessThanInteger-memory-arguments": 1, + "lessThanEqualsInteger-cpu-arguments-slope": 1366, + "fstPair-memory-arguments": 32, + "modInteger-memory-arguments-intercept": 0, + "unConstrData-cpu-arguments": 150000, + "lessThanEqualsInteger-memory-arguments": 1, + "chooseUnit-memory-arguments": 32, + "sndPair-memory-arguments": 32, + "addInteger-cpu-arguments-intercept": 197209, + "decodeUtf8-memory-arguments-slope": 8, + "equalsData-cpu-arguments-intercept": 150000, + "mapData-cpu-arguments": 150000, + "mkPairData-cpu-arguments": 150000, + "quotientInteger-cpu-arguments-constant": 148000, + "consByteString-memory-arguments-slope": 1, + "cekVarCost-exBudgetMemory": 100, + "indexByteString-cpu-arguments": 150000, + "unListData-cpu-arguments": 150000, + "equalsInteger-cpu-arguments-slope": 1326, + "cekStartupCost-exBudgetMemory": 100, + "subtractInteger-cpu-arguments-intercept": 197209, + "divideInteger-cpu-arguments-model-arguments-intercept": 425507, + "divideInteger-memory-arguments-intercept": 0, + "cekForceCost-exBudgetMemory": 100, + "blake2b-cpu-arguments-intercept": 2477736, + "remainderInteger-cpu-arguments-constant": 148000, + "tailList-cpu-arguments": 150000, + "encodeUtf8-cpu-arguments-intercept": 150000, + "equalsString-cpu-arguments-slope": 1000, + "lessThanByteString-memory-arguments": 1, + "multiplyInteger-cpu-arguments-slope": 11218, + "appendByteString-cpu-arguments-intercept": 396231, + "lessThanEqualsByteString-cpu-arguments-slope": 248, + "modInteger-memory-arguments-slope": 1, + "addInteger-cpu-arguments-slope": 0, + "equalsData-cpu-arguments-slope": 10000, + "decodeUtf8-memory-arguments-intercept": 0, + "chooseList-cpu-arguments": 150000, + "constrData-cpu-arguments": 150000, + "equalsByteString-memory-arguments": 1, + "cekApplyCost-exBudgetCPU": 29773, + "quotientInteger-memory-arguments-slope": 1, + "verifySignature-cpu-arguments-intercept": 3345831, + "unMapData-memory-arguments": 32, + "mkCons-memory-arguments": 32, + "sliceByteString-memory-arguments-slope": 1, + "sha3_256-memory-arguments": 4, + "ifThenElse-memory-arguments": 1, + "mkNilPairData-memory-arguments": 32, + "equalsByteString-cpu-arguments-slope": 247, + "appendString-cpu-arguments-intercept": 150000, + "quotientInteger-cpu-arguments-model-arguments-slope": 118, + "cekApplyCost-exBudgetMemory": 100, + "equalsString-memory-arguments": 1, + "multiplyInteger-memory-arguments-slope": 1, + "cekBuiltinCost-exBudgetMemory": 100, + "remainderInteger-memory-arguments-intercept": 0, + "sha2_256-cpu-arguments-intercept": 2477736, + "remainderInteger-cpu-arguments-model-arguments-intercept": 425507, + "lessThanEqualsByteString-memory-arguments": 1, + "tailList-memory-arguments": 32, + "mkNilData-cpu-arguments": 150000, + "chooseData-cpu-arguments": 150000, + "unBData-memory-arguments": 32, + "blake2b-memory-arguments": 4, + "iData-memory-arguments": 32, + "nullList-memory-arguments": 32, + "cekDelayCost-exBudgetCPU": 29773, + "subtractInteger-memory-arguments-intercept": 1, + "lessThanByteString-cpu-arguments-intercept": 103599, + "consByteString-cpu-arguments-slope": 1000, + "appendByteString-memory-arguments-slope": 1, + "trace-memory-arguments": 32, + "divideInteger-cpu-arguments-constant": 148000, + "cekConstCost-exBudgetCPU": 29773, + "encodeUtf8-memory-arguments-slope": 8, + "quotientInteger-cpu-arguments-model-arguments-intercept": 425507, + "mapData-memory-arguments": 32, + "appendString-cpu-arguments-slope": 1000, + "modInteger-cpu-arguments-constant": 148000, + "verifySignature-cpu-arguments-slope": 1, + "unConstrData-memory-arguments": 32, + "quotientInteger-memory-arguments-intercept": 0, + "equalsByteString-cpu-arguments-constant": 150000, + "sliceByteString-memory-arguments-intercept": 0, + "mkPairData-memory-arguments": 32, + "equalsByteString-cpu-arguments-intercept": 112536, + "appendString-memory-arguments-slope": 1, + "lessThanInteger-cpu-arguments-slope": 497, + "modInteger-cpu-arguments-model-arguments-intercept": 425507, + "modInteger-memory-arguments-minimum": 1, + "sha3_256-cpu-arguments-intercept": 0, + "verifySignature-memory-arguments": 1, + "cekLamCost-exBudgetMemory": 100, + "sliceByteString-cpu-arguments-intercept": 150000 + } + } +} diff --git a/cardano-api/test/cardano-api-test/files/input/node-config/byron-genesis.json b/cardano-api/test/cardano-api-test/files/input/node-config/byron-genesis.json new file mode 100644 index 0000000000..a1029805da --- /dev/null +++ b/cardano-api/test/cardano-api-test/files/input/node-config/byron-genesis.json @@ -0,0 +1,60 @@ +{ + "avvmDistr": { + "-0BJDi-gauylk4LptQTgjMeo7kY9lTCbZv12vwOSTZk=": "9999300000000", + "-0Np4pyTOWF26iXWVIvu6fhz9QupwWRS2hcCaOEYlw0=": "3760024000000", + "-0_pjw54ACGTrCsH3SXreedq-Cj9pFBcZDbxT9sXaqQ=": "411085000000" + }, + "blockVersionData": { + "heavyDelThd": "300000000000", + "maxBlockSize": "2000000", + "maxHeaderSize": "2000000", + "maxProposalSize": "700", + "maxTxSize": "4096", + "mpcThd": "20000000000000", + "scriptVersion": 0, + "slotDuration": "20000", + "softforkRule": { + "initThd": "900000000000000", + "minThd": "600000000000000", + "thdDecrement": "50000000000000" + }, + "txFeePolicy": { + "multiplier": "43946000000", + "summand": "155381000000000" + }, + "unlockStakeEpoch": "18446744073709551615", + "updateImplicit": "10000", + "updateProposalThd": "100000000000000", + "updateVoteThd": "1000000000000" + }, + "protocolConsts": { + "k": 2160, + "protocolMagic": 764824073, + "vssMaxTTL": 6, + "vssMinTTL": 2 + }, + "startTime": 1506203091, + "bootStakeholders": { + "1deb82908402c7ee3efeb16f369d97fba316ee621d09b32b8969e54b": 1, + "65904a89e6d0e5f881513d1736945e051b76f095eca138ee869d543d": 1, + "5411c7bf87c252609831a337a713e4859668cba7bba70a9c3ef7c398": 1 + }, + "heavyDelegation": { + "1deb82908402c7ee3efeb16f369d97fba316ee621d09b32b8969e54b": { + "cert": "c8b39f094dc00608acb2d20ff274cb3e0c022ccb0ce558ea7c1a2d3a32cd54b42cc30d32406bcfbb7f2f86d05d2032848be15b178e3ad776f8b1bc56a671400d", + "delegatePk": "6MA6A8Cy3b6kGVyvOfQeZp99JR7PIh+7LydcCl1+BdGQ3MJG9WyOM6wANwZuL2ZN2qmF6lKECCZDMI3eT1v+3w==", + "issuerPk": "UHMxYf2vtsjLb64OJb35VVEFs2eO+wjxd1uekN5PXHe8yM7/+NkBHLJ4so/dyG2bqwmWVtd6eFbHYZEIy/ZXUg==", + "omega": 0 + }, + "65904a89e6d0e5f881513d1736945e051b76f095eca138ee869d543d": { + "cert": "552741f728196e62f218047b944b24ce4d374300d04b9b281426f55aa000d53ded66989ad5ea0908e6ff6492001ff18ece6c7040a934060759e9ae09863bf203", + "delegatePk": "X93u2t4nFNbbL54RBHQ9LY2Bjs3cMG4XYQjbFMqt1EG0V9WEDGD4hAuZyPeMKQriKdT4Qx5ni6elRcNWB7lN2w==", + "issuerPk": "C9sfXvPZlAN1k/ImYlXxNKVkZYuy34FLO5zvuW2jT6nIiFkchbdw/TZybV89mRxmiCiv/Hu+CHL9aZE25mTZ2A==", + "omega": 0 + } + }, + "nonAvvmBalances": { + "2cWKMJemoBajGgvgVVziaKmUFa4LwJnAHffmuaSJBMDqethwJVQsyBsTSfFhp5jFpkVQM": "5428571428571429", + "37btjrVyb4KEg6anTcJ9E4EAvYtNV9xXL6LNpA15YLhgvm9zJ1D2jwme574HikZ36rKdTwaUmpEicCoL1bDw4CtH5PNcFnTRGQNaFd5ai6Wvo6CZsi": "19999999999999" + } +} diff --git a/cardano-api/test/cardano-api-test/files/input/node-config/conway-genesis.json b/cardano-api/test/cardano-api-test/files/input/node-config/conway-genesis.json new file mode 100644 index 0000000000..760995a34d --- /dev/null +++ b/cardano-api/test/cardano-api-test/files/input/node-config/conway-genesis.json @@ -0,0 +1,303 @@ +{ + "poolVotingThresholds": { + "committeeNormal": 0.51, + "committeeNoConfidence": 0.51, + "hardForkInitiation": 0.51, + "motionNoConfidence": 0.51, + "ppSecurityGroup": 0.51 + }, + "dRepVotingThresholds": { + "motionNoConfidence": 0.67, + "committeeNormal": 0.67, + "committeeNoConfidence": 0.6, + "updateToConstitution": 0.75, + "hardForkInitiation": 0.6, + "ppNetworkGroup": 0.67, + "ppEconomicGroup": 0.67, + "ppTechnicalGroup": 0.67, + "ppGovGroup": 0.75, + "treasuryWithdrawal": 0.67 + }, + "committeeMinSize": 7, + "committeeMaxTermLength": 146, + "govActionLifetime": 6, + "govActionDeposit": 100000000000, + "dRepDeposit": 500000000, + "dRepActivity": 20, + "minFeeRefScriptCostPerByte": 15, + "plutusV3CostModel": [ + 100788, + 420, + 1, + 1, + 1000, + 173, + 0, + 1, + 1000, + 59957, + 4, + 1, + 11183, + 32, + 201305, + 8356, + 4, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 100, + 100, + 16000, + 100, + 94375, + 32, + 132994, + 32, + 61462, + 4, + 72010, + 178, + 0, + 1, + 22151, + 32, + 91189, + 769, + 4, + 2, + 85848, + 123203, + 7305, + -900, + 1716, + 549, + 57, + 85848, + 0, + 1, + 1, + 1000, + 42921, + 4, + 2, + 24548, + 29498, + 38, + 1, + 898148, + 27279, + 1, + 51775, + 558, + 1, + 39184, + 1000, + 60594, + 1, + 141895, + 32, + 83150, + 32, + 15299, + 32, + 76049, + 1, + 13169, + 4, + 22100, + 10, + 28999, + 74, + 1, + 28999, + 74, + 1, + 43285, + 552, + 1, + 44749, + 541, + 1, + 33852, + 32, + 68246, + 32, + 72362, + 32, + 7243, + 32, + 7391, + 32, + 11546, + 32, + 85848, + 123203, + 7305, + -900, + 1716, + 549, + 57, + 85848, + 0, + 1, + 90434, + 519, + 0, + 1, + 74433, + 32, + 85848, + 123203, + 7305, + -900, + 1716, + 549, + 57, + 85848, + 0, + 1, + 1, + 85848, + 123203, + 7305, + -900, + 1716, + 549, + 57, + 85848, + 0, + 1, + 955506, + 213312, + 0, + 2, + 270652, + 22588, + 4, + 1457325, + 64566, + 4, + 20467, + 1, + 4, + 0, + 141992, + 32, + 100788, + 420, + 1, + 1, + 81663, + 32, + 59498, + 32, + 20142, + 32, + 24588, + 32, + 20744, + 32, + 25933, + 32, + 24623, + 32, + 43053543, + 10, + 53384111, + 14333, + 10, + 43574283, + 26308, + 10, + 16000, + 100, + 16000, + 100, + 962335, + 18, + 2780678, + 6, + 442008, + 1, + 52538055, + 3756, + 18, + 267929, + 18, + 76433006, + 8868, + 18, + 52948122, + 18, + 1995836, + 36, + 3227919, + 12, + 901022, + 1, + 166917843, + 4307, + 36, + 284546, + 36, + 158221314, + 26549, + 36, + 74698472, + 36, + 333849714, + 1, + 254006273, + 72, + 2174038, + 72, + 2261318, + 64571, + 4, + 207616, + 8310, + 4, + 1293828, + 28716, + 63, + 0, + 1, + 1006041, + 43623, + 251, + 0, + 1 + ], + "constitution": { + "anchor": { + "dataHash": "ca41a91f399259bcefe57f9858e91f6d00e1a38d6d9c63d4052914ea7bd70cb2", + "url": "ipfs://bafkreifnwj6zpu3ixa4siz2lndqybyc5wnnt3jkwyutci4e2tmbnj3xrdm" + }, + "script": "fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64" + }, + "committee": { + "members": { + "scriptHash-df0e83bde65416dade5b1f97e7f115cc1ff999550ad968850783fe50": 580, + "scriptHash-b6012034ba0a7e4afbbf2c7a1432f8824aee5299a48e38e41a952686": 580, + "scriptHash-ce8b37a72b178a37bbd3236daa7b2c158c9d3604e7aa667e6c6004b7": 580, + "scriptHash-f0dc2c00d92a45521267be2d5de1c485f6f9d14466d7e16062897cf7": 580, + "scriptHash-349e55f83e9af24813e6cb368df6a80d38951b2a334dfcdf26815558": 580, + "scriptHash-84aebcfd3e00d0f87af918fc4b5e00135f407e379893df7e7d392c6a": 580, + "scriptHash-e8165b3328027ee0d74b1f07298cb092fd99aa7697a1436f5997f625": 580 + }, + "threshold": { + "numerator": 2, + "denominator": 3 + } + } +} diff --git a/cardano-api/test/cardano-api-test/files/input/node-config/dijkstra-genesis.json b/cardano-api/test/cardano-api-test/files/input/node-config/dijkstra-genesis.json new file mode 100644 index 0000000000..60a45f2b85 --- /dev/null +++ b/cardano-api/test/cardano-api-test/files/input/node-config/dijkstra-genesis.json @@ -0,0 +1,28 @@ +{ + "maxRefScriptSizePerBlock": 1048576, + "maxRefScriptSizePerTx": 307200, + "refScriptCostStride": 25600, + "refScriptCostMultiplier": 1.2, + "minPoolMargin": 0.015, + "plutusV4CostModel": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "leiosAnnouncementPeriodLength": 1000, + "leiosVotePeriodLength": 4000, + "leiosDiffusionPeriodLength": 7000, + "leiosCommitteeSize": 900, + "leiosQuorumStakeThreshold": 0.75, + "maxEndorserBlockReferencesSize": 524288, + "maxEndorserBlockTxsSize": 12582912, + "maxEndorserBlockExecutionUnits": { + "memory": 7000000000, + "steps": 2000000000000 + }, + "maxRefScriptSizePerEndorserBlock": 12582912, + "perasMinCandidateBlockAge": 90, + "perasHealingFactor": 0.5, + "perasCertBoost": 15, + "perasTargetCommitteeSize": 800, + "perasBootstrapRound": 0, + "perasQuorumThresholdSafetyMargin": 0.05, + "refInputsCostPerMultiAssetPolicy": 0, + "refInputsCostPerDatumByte": 0 +} diff --git a/cardano-api/test/cardano-api-test/files/input/node-config/shelley-genesis.json b/cardano-api/test/cardano-api-test/files/input/node-config/shelley-genesis.json new file mode 100644 index 0000000000..87e463e249 --- /dev/null +++ b/cardano-api/test/cardano-api-test/files/input/node-config/shelley-genesis.json @@ -0,0 +1,48 @@ +{ + "activeSlotsCoeff": 0.05, + "protocolParams": { + "protocolVersion": { + "minor": 0, + "major": 2 + }, + "decentralisationParam": 1, + "eMax": 18, + "extraEntropy": { + "tag": "NeutralNonce" + }, + "maxTxSize": 16384, + "maxBlockBodySize": 65536, + "maxBlockHeaderSize": 1100, + "minFeeA": 44, + "minFeeB": 155381, + "minUTxOValue": 1000000, + "poolDeposit": 500000000, + "minPoolCost": 340000000, + "keyDeposit": 2000000, + "nOpt": 150, + "rho": 0.003, + "tau": 0.2, + "a0": 0.3 + }, + "genDelegs": { + "ad5463153dc3d24b9ff133e46136028bdc1edbb897f5a7cf1b37950c": { + "delegate": "d9e5c76ad5ee778960804094a389f0b546b5c2b140a62f8ec43ea54d", + "vrf": "64fa87e8b29a5b7bfbd6795677e3e878c505bc4a3649485d366b50abadec92d7" + }, + "b9547b8a57656539a8d9bc42c008e38d9c8bd9c8adbb1e73ad529497": { + "delegate": "855d6fc1e54274e331e34478eeac8d060b0b90c1f9e8a2b01167c048", + "vrf": "66d5167a1f426bd1adcc8bbf4b88c280d38c148d135cb41e3f5a39f948ad7fcc" + } + }, + "updateQuorum": 5, + "networkId": "Mainnet", + "initialFunds": {}, + "maxLovelaceSupply": 45000000000000000, + "networkMagic": 764824073, + "epochLength": 432000, + "systemStart": "2017-09-23T21:44:51Z", + "slotsPerKESPeriod": 129600, + "slotLength": 1, + "maxKESEvolutions": 62, + "securityParam": 2160 +} diff --git a/flake.lock b/flake.lock index efa167cd4c..f6915c9fb7 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "CHaP": { "flake": false, "locked": { - "lastModified": 1791300963, - "narHash": "sha256-Lk3dG1M/LUnPTaLQa4mSwe3RihB64Rmzb+kyFBwpnhc=", + "lastModified": 1792158310, + "narHash": "sha256-z2HpLRkWjY+v8WF77uExP/A21UuOxncdPS8WJR94vDk=", "owner": "intersectmbo", "repo": "cardano-haskell-packages", - "rev": "261233568f2690ef3d5faa2e081554fc9a7f0145", + "rev": "fcf7ce5365fdd58ecffe1e8639b9cf1a4735b38b", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 811d8b3c6e..c14b2458f7 100644 --- a/flake.nix +++ b/flake.nix @@ -275,6 +275,22 @@ proto-lens-protobuf-types.components.library.build-tools = [pkgs.buildPackages.protobuf]; }; }) + ({ + lib, + pkgs, + ... + }: + lib.mkIf pkgs.stdenv.hostPlatform.isWindows { + # unix-compat, which cardano-config brings in through trace-dispatcher, + # asks for msvcrt on Windows, but the toolchain links ucrt: the two C + # runtimes define the same symbols (__getmainargs, _onexit, tzset, ...), + # so no executable links. cardano-node carries the same fix + # (nix/haskell.nix). Remove once unix-compat stops asking for msvcrt: + # it still does in 0.7.4.1, its latest release, and on its master branch. + packages.unix-compat.postPatch = '' + sed -i 's/msvcrt//g' unix-compat.cabal + ''; + }) ]; }); # ... and construct a flake from the cabal project