Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,9 @@ configuration/cardano/mainnet-alonzo-genesis.json text eol=lf
configuration/cardano/mainnet-byron-genesis.json text eol=lf
configuration/cardano/mainnet-conway-genesis.json text eol=lf
configuration/cardano/mainnet-shelley-genesis.json text eol=lf
# Genesis hashes are taken over the raw file bytes, so a CRLF checkout on
# Windows would not match the hashes pinned in the fixture configurations.
cardano-node/test/cardano-config-compare/config/*.json text eol=lf

cardano-testnet/test/cardano-testnet-test/files/sample-proposal-anchor text eol=lf
cardano-testnet/test/cardano-testnet-test/files/sample-constitution-anchor text eol=lf
8 changes: 8 additions & 0 deletions cabal.project
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,11 @@ if impl(ghc >= 9.14)
-- Do NOT add more source-repository-package stanzas here unless they are strictly
-- temporary! Please read the section in CONTRIBUTING about updating dependencies.


-- TEMPORARY: cardano-config is not published to CHaP yet. Remove this stanza
-- (and depend on the CHaP release) as soon as it is.
source-repository-package
type: git
location: https://github.com/IntersectMBO/cardano-config
tag: 5f17f6c07f7fcccc67b5360da4339e2c16615b41
--sha256: sha256-IWkreOeztCXfx31MyDtC3PmdlO4vzfklQiB4L2XW5KU=
114 changes: 112 additions & 2 deletions cardano-node/app/cardano-node.hs
Original file line number Diff line number Diff line change
@@ -1,24 +1,38 @@
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TemplateHaskell #-}

import qualified Cardano.Configuration as Cfg
import qualified Cardano.Configuration.CliArgs as CliArgs
import qualified Cardano.Configuration.Commands as Cmds
import qualified Cardano.Crypto.Init as Crypto
import Cardano.Git.Rev (gitRev)
import Cardano.Node.Configuration.POM (PartialNodeConfiguration (..))
import Cardano.Node.Configuration.CardanoConfigAdapter
(cardanoConfigToNodeConfiguration)
import Cardano.Node.Configuration.CardanoConfigCompare
(compareConfigurations)
import Cardano.Node.Configuration.CardanoConfigResolve
(ConfigurationDialect (..), classifyConfigurationFile)
import Cardano.Node.Configuration.POM (NodeConfiguration (..),
PartialNodeConfiguration (..), defaultPartialNodeConfiguration,
makeNodeConfiguration, parseNodeConfigurationFP)
import Cardano.Node.Handlers.TopLevel
import Cardano.Node.Parsers (nodeCLIParser)
import Cardano.Node.Run (runNode)
import Cardano.Node.Tracing.Documentation (TraceDocumentationCmd (..),
parseTraceDocumentationCmd, runTraceDocumentationCmd)
import Cardano.Node.Types (ConfigYamlFilePath (..))

import Data.Monoid (Last (getLast))
import Data.Monoid (Last (..))
import qualified Data.Text as Text
import qualified Data.Text.IO as Text
import Data.Version (showVersion)
import Options.Applicative
import qualified Options.Applicative as Opt
import System.Exit (exitFailure)
import System.Info (arch, compilerName, compilerVersion, os)
import System.IO (hPutStrLn, stderr)

Expand All @@ -37,6 +51,7 @@ main = do
runNode args
TraceDocumentation tdc -> runTraceDocumentationCmd tdc
VersionCmd -> runVersionCommand
ConfigCmd act -> act

where
p = Opt.prefs Opt.showHelpOnEmpty
Expand All @@ -56,6 +71,7 @@ main = do
Opt.info (fmap RunCmd nodeCLIParser
<|> fmap TraceDocumentation parseTraceDocumentationCmd
<|> parseVersionCmd
<|> fmap ConfigCmd configSubcommands
<**> helper)

( Opt.fullDesc <>
Expand All @@ -66,6 +82,7 @@ main = do
data Command = RunCmd PartialNodeConfiguration
| TraceDocumentation TraceDocumentationCmd
| VersionCmd
| ConfigCmd (IO ())

-- Yes! A --version flag or version command. Either guess is right!
parseVersionCmd :: Parser Command
Expand Down Expand Up @@ -105,3 +122,96 @@ command' c descr p =
[ command c (info (p <**> helper) $ mconcat [ progDesc descr ])
, metavar c
]

-- cardano-config subcommands --------------------------------------------------

-- | The @migrate@, @schema@ and @resolve@ subcommands, spliced from the shared
-- @cardano-config:commands@ sublibrary. @migrate@ and @schema@ are
-- cardano-config's own commands, unchanged; @resolve@ is a node-specific variant
-- (see 'resolveDualCommand') that additionally cross-checks the node's own parser
-- against cardano-config's.
configSubcommands :: Parser (IO ())
configSubcommands =
Opt.hsubparser
( Opt.commandGroup "Configuration commands:"
<> Cmds.migrateCommand
<> Cmds.schemaCommand
<> resolveDualCommand
)

-- | A node-specific @resolve@: resolve the configuration with cardano-config
-- (printing the result as YAML, exactly like cardano-config's own @resolve@) and,
-- for a legacy configuration, re-resolve it with the node's own POM parser and
-- report any discrepancies between the two. Exits non-zero when they disagree, so
-- it doubles as a CI parity check while the node still has two parsers.
--
-- A cardano-config envelope configuration has nothing to cross-check against:
-- the POM parser cannot read it (which is the whole point of the envelope), so
-- @resolve@ just prints the cardano-config result and says so.
resolveDualCommand :: Mod CommandFields (IO ())
resolveDualCommand =
command "resolve"
( info
(runDualResolve <$> Cmds.resolveOptionsParser)
( progDesc
( "Resolve a cardano-node configuration (defaults + file + CLI) and print the "
<> "result as YAML. A legacy (pre-cardano-config) configuration is resolved "
<> "with both the node and cardano-config parsers and any discrepancy between "
<> "them is reported (exit non-zero if they disagree)."
)
)
)

runDualResolve :: Cmds.ResolveOptions -> IO ()
runDualResolve resolveOpts@(Cmds.ResolveOptions cli _geneses) = do
-- Print the resolved configuration using cardano-config's own renderer (which
-- honours --with-geneses); this also terminates via 'die' if resolution fails.
Cmds.runResolveCommand resolveOpts
classifyConfigurationFile configFp >>= \case
CardanoConfigDialect ->
putStrLn $
"resolve: this is a cardano-config envelope configuration; the node's own parser"
<> " cannot read it, so there is nothing to cross-check."
LegacyDialect -> do
discrepancies <- resolveDiscrepancies cli
case discrepancies of
[] ->
putStrLn "resolve: the node and cardano-config parsers agree on the resolved configuration."
ds -> do
hPutStrLn stderr $
"resolve: " <> show (length ds)
<> " discrepancy(ies) between the node and cardano-config parsers:"
mapM_ (hPutStrLn stderr . (" - " <>)) ds
exitFailure
where
configFp = CliArgs.configFilePath cli

-- | Resolve a legacy configuration file (+ CLI) both ways and return the
-- divergences. The node (POM) side takes its CLI-supplied, file-absent fields
-- (topology / database / protocol files / socket) from the shared cardano-config
-- resolution, so the diff reflects how the two parsers read the configuration
-- FILE (plus the documented adapter gaps) rather than an independent — and
-- necessarily asymmetric — CLI reverse-mapping.
resolveDiscrepancies :: Cfg.CliArgs -> IO [String]
resolveDiscrepancies cli = do
(fileCfg, _warns) <- Cfg.parseConfigurationFiles configFp
case Cfg.resolveConfiguration cli fileCfg of
Left err -> pure ["cardano-config failed to resolve the configuration: " <> show err]
Right (cfgNc, _) ->
case cardanoConfigToNodeConfiguration cfgNc of
Left adaptErr -> pure ["cardano-config configuration could not be adapted: " <> adaptErr]
Right adaptedNc -> do
filePartial <- parseNodeConfigurationFP (Just (ConfigYamlFilePath configFp))
let withCli =
(defaultPartialNodeConfiguration <> filePartial)
{ pncConfigFile = Last (Just (ConfigYamlFilePath configFp))
, pncTopologyFile = Last (Just (ncTopologyFile adaptedNc))
, pncDatabaseFile = Last (Just (ncDatabaseFile adaptedNc))
, pncProtocolFiles = Last (Just (ncProtocolFiles adaptedNc))
, pncSocketConfig = Last (Just (ncSocketConfig adaptedNc))
}
case makeNodeConfiguration withCli of
Left err -> pure ["node parser (makeNodeConfiguration) failed: " <> err]
Right pomNc -> pure (compareConfigurations pomNc adaptedNc)
where
configFp = CliArgs.configFilePath cli
23 changes: 22 additions & 1 deletion cardano-node/cardano-node.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ license-files: LICENSE
NOTICE
build-type: Simple
extra-doc-files: ChangeLog.md
extra-source-files: test/cardano-config-compare/config/*.json

Flag unexpected_thunks
Description: Turn on unexpected thunks checks
Expand Down Expand Up @@ -69,7 +70,10 @@ library

hs-source-dirs: src

exposed-modules: Cardano.Node.Configuration.NodeAddress
exposed-modules: Cardano.Node.Configuration.CardanoConfigAdapter
Cardano.Node.Configuration.CardanoConfigCompare
Cardano.Node.Configuration.CardanoConfigResolve
Cardano.Node.Configuration.NodeAddress
Cardano.Node.Configuration.POM
Cardano.Node.Configuration.LedgerDB
Cardano.Node.Configuration.Socket
Expand Down Expand Up @@ -134,6 +138,7 @@ library
, base16-bytestring
, bytestring
, cardano-api ^>= 11.6
, cardano-config
, cardano-data
, cardano-crypto-class ^>=2.5
, cardano-crypto-wrapper
Expand Down Expand Up @@ -217,12 +222,28 @@ executable cardano-node
autogen-modules: Paths_cardano_node

build-depends: base
, cardano-config
, cardano-config:commands
, cardano-crypto-class
, cardano-git-rev
, cardano-node
, optparse-applicative
, text

test-suite cardano-config-compare-test
import: project-config
hs-source-dirs: test/cardano-config-compare
main-is: Main.hs
type: exitcode-stdio-1.0

build-depends: base
, cardano-config
, cardano-node
, directory
, filepath
, tasty
, tasty-hunit

test-suite cardano-node-test
import: project-config
, maybe-unix
Expand Down
Loading
Loading