Skip to content

Commit

Permalink
Merge pull request #923 from IntersectMBO/smelc/check-node-config
Browse files Browse the repository at this point in the history
Add check-node-configuration command
  • Loading branch information
smelc authored Oct 31, 2024
2 parents 447fa87 + 38f2ef5 commit eb9595e
Show file tree
Hide file tree
Showing 19 changed files with 1,072 additions and 4 deletions.
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ cardano-cli/test/cardano-cli-golden/files/input/example_anchor_data.txt -text
cardano-cli/test/cardano-cli-golden/files/input/example_anchor_data2.txt -text
cardano-cli/test/cardano-cli-test/files/input/example_anchor_data.txt -text
cardano-cli/test/cardano-cli-test/files/input/example_anchor_data2.txt -text
cardano-cli/test/cardano-cli-test/files/input/check-node-configuration/genesis.alonzo.spec.json -text
cardano-cli/test/cardano-cli-test/files/input/check-node-configuration/genesis.byron.spec.json -text
cardano-cli/test/cardano-cli-test/files/input/check-node-configuration/genesis.conway.spec.json -text
cardano-cli/test/cardano-cli-test/files/input/check-node-configuration/genesis.shelley.spec.json -text
5 changes: 5 additions & 0 deletions cardano-cli/cardano-cli.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ library
Cardano.CLI.Commands
Cardano.CLI.Commands.Address
Cardano.CLI.Commands.Debug
Cardano.CLI.Commands.Debug.CheckNodeConfiguration
Cardano.CLI.Commands.Debug.LogEpochState
Cardano.CLI.Commands.Debug.TransactionView
Cardano.CLI.Commands.Hash
Expand Down Expand Up @@ -141,6 +142,7 @@ library
Cardano.CLI.Run.Address
Cardano.CLI.Run.Address.Info
Cardano.CLI.Run.Debug
Cardano.CLI.Run.Debug.CheckNodeConfiguration
Cardano.CLI.Run.Debug.LogEpochState
Cardano.CLI.Run.Debug.TransactionView
Cardano.CLI.Run.Hash
Expand Down Expand Up @@ -306,6 +308,7 @@ test-suite cardano-cli-test
type: exitcode-stdio-1.0
build-depends:
aeson,
aeson-pretty,
base16-bytestring,
bech32 >=1.1.0,
bytestring,
Expand All @@ -327,10 +330,12 @@ test-suite cardano-cli-test
text,
time,
transformers,
yaml,

build-tool-depends: tasty-discover:tasty-discover
other-modules:
Test.Cli.AddCostModels
Test.Cli.CheckNodeConfiguration
Test.Cli.CreateCardano
Test.Cli.CreateTestnetData
Test.Cli.DRepMetadata
Expand Down
4 changes: 3 additions & 1 deletion cardano-cli/src/Cardano/CLI/Commands/Debug.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ module Cardano.CLI.Commands.Debug
)
where

import Cardano.CLI.Commands.Debug.CheckNodeConfiguration
import Cardano.CLI.Commands.Debug.LogEpochState
import Cardano.CLI.Commands.Debug.TransactionView

data DebugCmds
= DebugLogEpochStateCmd LogEpochStateCmdArgs
= DebugCheckNodeConfigurationCmd CheckNodeConfigCmdArgs
| DebugLogEpochStateCmd LogEpochStateCmdArgs
| DebugTransactionViewCmd TransactionViewCmdArgs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{-# LANGUAGE DataKinds #-}

module Cardano.CLI.Commands.Debug.CheckNodeConfiguration where

import Cardano.Api

-- | Argument for the 'debug check-node-configuration' command.
newtype CheckNodeConfigCmdArgs = CheckNodeConfigCmdArgs (NodeConfigFile 'In)
deriving Show
10 changes: 10 additions & 0 deletions cardano-cli/src/Cardano/CLI/Options/Debug.hs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ where
import Cardano.Api.Shelley hiding (QueryInShelleyBasedEra (..))

import Cardano.CLI.Commands.Debug
import Cardano.CLI.Commands.Debug.CheckNodeConfiguration
import Cardano.CLI.Commands.Debug.LogEpochState
import Cardano.CLI.Commands.Debug.TransactionView
import Cardano.CLI.Environment
Expand Down Expand Up @@ -47,6 +48,10 @@ pDebugCmds envCli =
, " The log file format is line delimited JSON."
, " The command will not terminate."
]
, subParser "check-node-configuration" $
Opt.info pCheckNodeConfigurationCmdArgs $
Opt.progDesc
"Check hashes and paths of genesis files in the given node configuration file."
, subParser "transaction" $
Opt.info
( asum
Expand All @@ -65,6 +70,11 @@ pDebugCmds envCli =
<*> pFileOutDirection
"out-file"
"Output filepath of the log file. The log file format is line delimited JSON."
pCheckNodeConfigurationCmdArgs :: Parser DebugCmds
pCheckNodeConfigurationCmdArgs =
fmap DebugCheckNodeConfigurationCmd $
CheckNodeConfigCmdArgs
<$> pNodeConfigurationFileIn
pTransactionView :: Parser DebugCmds
pTransactionView =
fmap DebugTransactionViewCmd $
Expand Down
15 changes: 14 additions & 1 deletion cardano-cli/src/Cardano/CLI/Read.hs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ module Cardano.CLI.Read
, readVoteDelegationTarget
, readVerificationKeyOrHashOrFileOrScript
, readVerificationKeySource

-- * Genesis hashes
, readShelleyOnwardsGenesisAndHash
)
where

Expand All @@ -108,7 +111,7 @@ import Cardano.CLI.Types.Errors.ScriptDecodeError
import Cardano.CLI.Types.Errors.StakeCredentialError
import Cardano.CLI.Types.Governance
import Cardano.CLI.Types.Key
import qualified Cardano.Crypto.Hash.Class as Crypto
import qualified Cardano.Crypto.Hash as Crypto

import Prelude

Expand Down Expand Up @@ -1227,3 +1230,13 @@ readVoteDelegationTarget voteDelegationTarget =
pure L.DRepAlwaysAbstain
VoteDelegationTargetOfNoConfidence ->
pure L.DRepAlwaysNoConfidence

--- | Read the given file and hashes its content using 'Blake2b_256'
readShelleyOnwardsGenesisAndHash
:: MonadIO m
=> FilePath
-- ^ The file to read
-> m (Crypto.Hash Crypto.Blake2b_256 BS.ByteString)
readShelleyOnwardsGenesisAndHash path = do
content <- liftIO $ BS.readFile path
return $ Crypto.hashWith id content
2 changes: 2 additions & 0 deletions cardano-cli/src/Cardano/CLI/Run/Debug.hs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ where
import Cardano.Api

import Cardano.CLI.Commands.Debug
import Cardano.CLI.Run.Debug.CheckNodeConfiguration (runCheckNodeConfig)
import Cardano.CLI.Run.Debug.LogEpochState
import Cardano.CLI.Run.Debug.TransactionView (runTransactionViewCmd)
import Cardano.CLI.Types.Errors.DebugCmdError

runDebugCmds :: DebugCmds -> ExceptT DebugCmdError IO ()
runDebugCmds = \case
DebugCheckNodeConfigurationCmd cmd -> runCheckNodeConfig cmd
DebugLogEpochStateCmd cmd -> liftIO $ runLogEpochStateCmd cmd
DebugTransactionViewCmd cmd -> firstExceptT DebugTxCmdError $ runTransactionViewCmd cmd
91 changes: 91 additions & 0 deletions cardano-cli/src/Cardano/CLI/Run/Debug/CheckNodeConfiguration.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Cardano.CLI.Run.Debug.CheckNodeConfiguration (runCheckNodeConfig) where

import Cardano.Api
import qualified Cardano.Api.Byron as Byron

import Cardano.CLI.Commands.Debug.CheckNodeConfiguration
import qualified Cardano.CLI.Read as Read
import Cardano.CLI.Types.Errors.DebugCmdError
import qualified Cardano.Crypto.Hash as Crypto

import Control.Monad
import qualified Data.Text as Text
import qualified Data.Yaml as Yaml
import System.FilePath (takeDirectory, (</>))

runCheckNodeConfig :: CheckNodeConfigCmdArgs -> ExceptT DebugCmdError IO ()
runCheckNodeConfig (CheckNodeConfigCmdArgs configFile) = do
nodeConfig :: NodeConfig <- liftIO $ Yaml.decodeFileThrow configFilePath
checkNodeGenesisConfiguration configFile nodeConfig
liftIO $ putStrLn $ "Successfully checked node configuration file: " <> configFilePath
where
configFilePath = unFile configFile

checkNodeGenesisConfiguration
:: NodeConfigFile 'In
-- ^ The node configuration file path. It's not read by this function, but used for producing error messages.
-> NodeConfig
-- ^ The parsed node configuration file
-> ExceptT DebugCmdError IO ()
checkNodeGenesisConfiguration configFile nodeConfig = do
let byronGenFile = adjustFilepath $ unFile $ ncByronGenesisFile nodeConfig
alonzoGenFile = adjustFilepath $ unFile $ ncAlonzoGenesisFile nodeConfig
shelleyGenFile = adjustFilepath $ unFile $ ncShelleyGenesisFile nodeConfig
conwayGenFile <- case ncConwayGenesisFile nodeConfig of
Nothing -> throwError $ DebugNodeConfigNoConwayFileCmdError configFilePath
Just conwayGenesisFile -> pure $ adjustFilepath $ unFile conwayGenesisFile

liftIO $ putStrLn $ "Checking byron genesis file: " <> byronGenFile

let expectedByronHash = unGenesisHashByron $ ncByronGenesisHash nodeConfig
expectedAlonzoHash = Crypto.hashToTextAsHex $ unGenesisHashAlonzo $ ncAlonzoGenesisHash nodeConfig
expectedShelleyHash = Crypto.hashToTextAsHex $ unGenesisHashShelley $ ncShelleyGenesisHash nodeConfig
expectedConwayHash <- case ncConwayGenesisHash nodeConfig of
Nothing -> throwError $ DebugNodeConfigNoConwayHashCmdError configFilePath
Just conwayGenesisHash -> pure $ Crypto.hashToTextAsHex $ unGenesisHashConway conwayGenesisHash

(_, Byron.GenesisHash byronHash) <-
firstExceptT (DebugNodeConfigGenesisDataCmdError byronGenFile) $
Byron.readGenesisData byronGenFile
let actualByronHash = Text.pack $ show byronHash
actualAlonzoHash <- Crypto.hashToTextAsHex <$> Read.readShelleyOnwardsGenesisAndHash alonzoGenFile
actualShelleyHash <- Crypto.hashToTextAsHex <$> Read.readShelleyOnwardsGenesisAndHash shelleyGenFile
actualConwayHash <- Crypto.hashToTextAsHex <$> Read.readShelleyOnwardsGenesisAndHash conwayGenFile

when (actualByronHash /= expectedByronHash) $
throwError $
DebugNodeConfigWrongGenesisHashCmdError
configFilePath
byronGenFile
actualByronHash
expectedByronHash
when (actualAlonzoHash /= expectedAlonzoHash) $
throwError $
DebugNodeConfigWrongGenesisHashCmdError
configFilePath
alonzoGenFile
actualAlonzoHash
expectedAlonzoHash
when (actualShelleyHash /= expectedShelleyHash) $
throwError $
DebugNodeConfigWrongGenesisHashCmdError
configFilePath
shelleyGenFile
actualShelleyHash
expectedShelleyHash
when (actualConwayHash /= expectedConwayHash) $
throwError $
DebugNodeConfigWrongGenesisHashCmdError
configFilePath
conwayGenFile
actualConwayHash
expectedConwayHash
where
configFilePath = unFile configFile
-- We make the genesis filepath relative to the node configuration file, like the node does:
-- https://github.com/IntersectMBO/cardano-node/blob/9671e7b6a1b91f5a530722937949b86deafaad43/cardano-node/src/Cardano/Node/Configuration/POM.hs#L668
-- Note that, if the genesis filepath is absolute, the node configuration file's directory is ignored (by property of </>)
adjustFilepath f = takeDirectory configFilePath </> f
52 changes: 52 additions & 0 deletions cardano-cli/src/Cardano/CLI/Types/Errors/DebugCmdError.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,66 @@ module Cardano.CLI.Types.Errors.DebugCmdError
where

import Cardano.Api
import qualified Cardano.Api.Byron as Byron

import Cardano.CLI.Types.Errors.TxCmdError

import Data.Text (Text)
import qualified Data.Text.Lazy.Builder as Text
import Formatting.Buildable (build)

data DebugCmdError
= DebugCmdFailed
| -- | @DebugNodeConfigGenesisDataCmdError filepath error@ represents an error when
-- reading the node configuration at @filepath@
DebugNodeConfigGenesisDataCmdError !FilePath !Byron.GenesisDataError
| -- | @DebugNodeConfigWrongGenesisHashCmdError filepath eraGenesisPath actualHash expectedHash@ represents a user error
-- that the hash of @eraGenesisPath@ in @filepath@ is @actualHash@, whereas it should be @expectedHash@
DebugNodeConfigWrongGenesisHashCmdError
!FilePath
-- ^ The file path of the node configuration file
!FilePath
-- ^ The file path of the era configuration file whose hash is wrong
!Text
-- ^ The actual hash (the hash found by hashing the genesis file)
!Text
-- ^ The expected hash (the hash mentioned in the configuration file)
| -- | @DebugNodeConfigNoConwayFileCmdError filepath@ represents a user error
-- that the genesis file for Conway in @filepath@ is not specified
DebugNodeConfigNoConwayFileCmdError
!FilePath
| -- | @DebugNodeConfigNoConwayHashCmdError filepath@ represents a user error
-- that the hash for the Conway genesis file in @filepath@ is not specified
DebugNodeConfigNoConwayHashCmdError
!FilePath
-- ^ The file path of the node configuration file
| DebugTxCmdError !TxCmdError

instance Error DebugCmdError where
prettyError = \case
DebugCmdFailed -> "Debug command failed"
DebugNodeConfigGenesisDataCmdError fp err ->
"Error reading node configuration at: "
<> pretty fp
<> ": "
<> pretty (Text.toLazyText $ build err)
DebugNodeConfigNoConwayFileCmdError fp ->
"Conway genesis file not specified in "
<> pretty fp
<> ". Please add a \"ConwayGenesisFile\" key to the file at "
<> pretty fp
DebugNodeConfigNoConwayHashCmdError fp ->
"Conway genesis hash not specified in "
<> pretty fp
<> ". Please add a \"ConwayGenesisHash\" key to the file at "
<> pretty fp
DebugNodeConfigWrongGenesisHashCmdError nodeFp genesisFp actualHash expectedHash ->
"Wrong genesis hash for "
<> pretty genesisFp
<> " in "
<> pretty nodeFp
<> ": when computing the hash, got: "
<> pretty actualHash
<> ", but the node configuration files states that this hash is expected: "
<> pretty expectedHash
DebugTxCmdError err -> renderTxCmdError err
10 changes: 9 additions & 1 deletion cardano-cli/test/cardano-cli-golden/files/golden/help.cli
Original file line number Diff line number Diff line change
Expand Up @@ -10613,7 +10613,11 @@ Usage: cardano-cli ping [-c|--count COUNT]

Ping a cardano node either using node-to-node or node-to-client protocol. It negotiates a handshake and keeps sending keep alive messages.

Usage: cardano-cli debug (log-epoch-state | transaction)
Usage: cardano-cli debug
( log-epoch-state
| check-node-configuration
| transaction
)

Debug commands

Expand All @@ -10625,6 +10629,10 @@ Usage: cardano-cli debug log-epoch-state --socket-path SOCKET_PATH
and log the epoch state to a file. The log file format is line delimited JSON.
The command will not terminate.

Usage: cardano-cli debug check-node-configuration --node-configuration-file FILEPATH

Check hashes and paths of genesis files in the given node configuration file.

Usage: cardano-cli debug transaction view

Transaction commands
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
Usage: cardano-cli debug (log-epoch-state | transaction)
Usage: cardano-cli debug
( log-epoch-state
| check-node-configuration
| transaction
)

Debug commands

Expand All @@ -10,4 +14,6 @@ Available commands:
connect to a local node and log the epoch state to a
file. The log file format is line delimited JSON. The
command will not terminate.
check-node-configuration Check hashes and paths of genesis files in the given
node configuration file.
transaction Transaction commands
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Usage: cardano-cli debug check-node-configuration --node-configuration-file FILEPATH

Check hashes and paths of genesis files in the given node configuration file.

Available options:
--node-configuration-file FILEPATH
Input filepath of the node configuration file.
-h,--help Show this help text
Loading

0 comments on commit eb9595e

Please sign in to comment.