diff --git a/cardano-cli/cardano-cli.cabal b/cardano-cli/cardano-cli.cabal index 1ecf223ed1..1e6bd31539 100644 --- a/cardano-cli/cardano-cli.cabal +++ b/cardano-cli/cardano-cli.cabal @@ -335,6 +335,7 @@ test-suite cardano-cli-test Test.Cli.AddCostModels Test.Cli.CreateCardano Test.Cli.CreateTestnetData + Test.Cli.DRepMetadata Test.Cli.FilePermissions Test.Cli.Governance.DRep Test.Cli.Governance.Hash diff --git a/cardano-cli/src/Cardano/CLI/EraBased/Commands/Governance/DRep.hs b/cardano-cli/src/Cardano/CLI/EraBased/Commands/Governance/DRep.hs index b1e10d780e..8ef5e2e088 100644 --- a/cardano-cli/src/Cardano/CLI/EraBased/Commands/Governance/DRep.hs +++ b/cardano-cli/src/Cardano/CLI/EraBased/Commands/Governance/DRep.hs @@ -11,10 +11,13 @@ module Cardano.CLI.EraBased.Commands.Governance.DRep , GovernanceDRepRetirementCertificateCmdArgs (..) , GovernanceDRepUpdateCertificateCmdArgs (..) , GovernanceDRepMetadataHashCmdArgs (..) + , DRepMetadataSource (..) + , DRepHashGoal (..) ) where import Cardano.Api +import qualified Cardano.Api.Ledger as L import Cardano.CLI.Types.Common import Cardano.CLI.Types.Key @@ -81,10 +84,24 @@ data GovernanceDRepUpdateCertificateCmdArgs era data GovernanceDRepMetadataHashCmdArgs era = GovernanceDRepMetadataHashCmdArgs { eon :: !(ConwayEraOnwards era) - , metadataFile :: !(DRepMetadataFile In) - , mOutFile :: !(Maybe (File () Out)) + , drepMetadataSource :: !DRepMetadataSource + , hashGoal :: !DRepHashGoal } +data DRepMetadataSource + = DrepMetadataFileIn !(DRepMetadataFile In) + | DrepMetadataURL !L.Url + deriving Show + +data DRepHashGoal + = -- | The hash is written to stdout + DRepHashToStdout + | -- | The hash to check against + CheckDRepHash !(Hash DRepMetadata) + | -- | The output file to which the hash is written + DRepHashToFile !(File () Out) + deriving Show + renderGovernanceDRepCmds :: () => GovernanceDRepCmds era diff --git a/cardano-cli/src/Cardano/CLI/EraBased/Options/Governance/DRep.hs b/cardano-cli/src/Cardano/CLI/EraBased/Options/Governance/DRep.hs index 506233cfb1..63f9587595 100644 --- a/cardano-cli/src/Cardano/CLI/EraBased/Options/Governance/DRep.hs +++ b/cardano-cli/src/Cardano/CLI/EraBased/Options/Governance/DRep.hs @@ -10,7 +10,9 @@ module Cardano.CLI.EraBased.Options.Governance.DRep where import Cardano.Api +import Cardano.Api.Ledger (extractHash) import qualified Cardano.Api.Ledger as L +import Cardano.Api.Shelley (Hash (DRepMetadataHash)) import Cardano.CLI.Environment import Cardano.CLI.EraBased.Commands.Governance.DRep @@ -19,6 +21,7 @@ import Cardano.CLI.Parser import Cardano.CLI.Read import Cardano.CLI.Types.Common import Cardano.CLI.Types.Key +import Cardano.Ledger.SafeHash (castSafeHash) import Control.Applicative import Data.Foldable @@ -129,6 +132,19 @@ pDrepMetadataUrl = AnchorUrl <$> pUrl "drep-metadata-url" "DRep anchor URL" +pExpectedDrepMetadataHash :: Parser (Hash DRepMetadata) +pExpectedDrepMetadataHash = + Opt.option (DRepMetadataHash . extractHash . castSafeHash <$> readSafeHash) $ + mconcat + [ Opt.long "expected-hash" + , Opt.metavar "HASH" + , Opt.help $ + mconcat + [ "Expected hash for the DRep metadata, for verification purposes. " + , "If provided, the hash of the DRep metadata is compared to this value." + ] + ] + pDrepMetadataHash :: Parser (L.SafeHash L.StandardCrypto L.AnchorData) pDrepMetadataHash = Opt.option readSafeHash $ @@ -188,10 +204,26 @@ pGovernanceDrepMetadataHashCmd era = do $ Opt.info ( fmap GovernanceDRepMetadataHashCmd $ GovernanceDRepMetadataHashCmdArgs w - <$> pFileInDirection "drep-metadata-file" "JSON Metadata file to hash." - <*> pMaybeOutputFile + <$> pDRepMetadataSource + <*> pDRepHashGoal ) - $ Opt.progDesc "Calculate the hash of a metadata file." + $ Opt.progDesc + "Calculate the hash of a metadata file, optionally checking the obtained hash against an expected value." + +pDRepHashGoal :: Parser DRepHashGoal +pDRepHashGoal = + asum + [ CheckDRepHash <$> pExpectedDrepMetadataHash + , DRepHashToFile <$> pOutputFile + ] + <|> pure DRepHashToStdout + +pDRepMetadataSource :: Parser DRepMetadataSource +pDRepMetadataSource = + asum + [ DrepMetadataFileIn <$> pFileInDirection "drep-metadata-file" "JSON Metadata file to hash." + , DrepMetadataURL <$> pUrl "drep-metadata-url" "URL pointing to the JSON Metadata file to hash." + ] -------------------------------------------------------------------------------- diff --git a/cardano-cli/src/Cardano/CLI/EraBased/Run/Governance/DRep.hs b/cardano-cli/src/Cardano/CLI/EraBased/Run/Governance/DRep.hs index b787fe5019..84499fc860 100644 --- a/cardano-cli/src/Cardano/CLI/EraBased/Run/Governance/DRep.hs +++ b/cardano-cli/src/Cardano/CLI/EraBased/Run/Governance/DRep.hs @@ -18,17 +18,19 @@ where import Cardano.Api import qualified Cardano.Api.Ledger as L +import Cardano.CLI.EraBased.Commands.Governance.DRep (DRepHashGoal (..)) import qualified Cardano.CLI.EraBased.Commands.Governance.DRep as Cmd import qualified Cardano.CLI.EraBased.Run.Key as Key -import Cardano.CLI.Run.Hash (getByteStringFromURL, httpsAndIpfsSchemas) +import Cardano.CLI.Run.Hash (allSchemas, getByteStringFromURL, httpsAndIpfsSchemas) import Cardano.CLI.Types.Common import Cardano.CLI.Types.Errors.CmdError import Cardano.CLI.Types.Errors.GovernanceCmdError -import Cardano.CLI.Types.Errors.HashCmdError (HashCheckError (..)) +import Cardano.CLI.Types.Errors.HashCmdError (FetchURLError, HashCheckError (..)) import Cardano.CLI.Types.Errors.RegistrationError import Cardano.CLI.Types.Key import Control.Monad (void, when) +import Data.ByteString (ByteString) import Data.Function import qualified Data.Text.Encoding as Text @@ -178,16 +180,37 @@ runGovernanceDRepMetadataHashCmd -> ExceptT GovernanceCmdError IO () runGovernanceDRepMetadataHashCmd Cmd.GovernanceDRepMetadataHashCmdArgs - { metadataFile - , mOutFile + { drepMetadataSource + , hashGoal } = do - metadataBytes <- firstExceptT ReadFileError . newExceptT $ readByteStringFile metadataFile + metadataBytes <- case drepMetadataSource of + Cmd.DrepMetadataFileIn metadataFile -> + firstExceptT ReadFileError . newExceptT $ readByteStringFile metadataFile + Cmd.DrepMetadataURL urlText -> + fetchURLToGovernanceCmdError $ getByteStringFromURL allSchemas urlText let (_metadata, metadataHash) = hashDRepMetadata metadataBytes - firstExceptT WriteFileError - . newExceptT - . writeByteStringOutput mOutFile - . serialiseToRawBytesHex - $ metadataHash + case hashGoal of + CheckDRepHash expectedHash + | metadataHash /= expectedHash -> + left $ GovernanceCmdHashMismatchError expectedHash metadataHash + | otherwise -> liftIO $ putStrLn "Hashes match!" + DRepHashToFile outFile -> writeOutput (Just outFile) metadataHash + DRepHashToStdout -> writeOutput Nothing metadataHash + where + writeOutput + :: MonadIO m + => Maybe (File content Out) + -> Hash DRepMetadata + -> ExceptT GovernanceCmdError m () + writeOutput mOutFile = + firstExceptT WriteFileError + . newExceptT + . writeByteStringOutput mOutFile + . serialiseToRawBytesHex + + fetchURLToGovernanceCmdError + :: ExceptT FetchURLError IO ByteString -> ExceptT GovernanceCmdError IO ByteString + fetchURLToGovernanceCmdError = withExceptT GovernanceCmdFetchURLError -- | Check the hash of the anchor data against the hash in the anchor if -- checkHash is set to CheckHash. diff --git a/cardano-cli/src/Cardano/CLI/Types/Errors/GovernanceCmdError.hs b/cardano-cli/src/Cardano/CLI/Types/Errors/GovernanceCmdError.hs index f3713d7a65..f6f82d3801 100644 --- a/cardano-cli/src/Cardano/CLI/Types/Errors/GovernanceCmdError.hs +++ b/cardano-cli/src/Cardano/CLI/Types/Errors/GovernanceCmdError.hs @@ -9,7 +9,7 @@ import Cardano.Api.Shelley import Cardano.Binary (DecoderError) import Cardano.CLI.Read -import Cardano.CLI.Types.Errors.HashCmdError (HashCheckError) +import Cardano.CLI.Types.Errors.HashCmdError (FetchURLError, HashCheckError) import Cardano.CLI.Types.Errors.StakeAddressCmdError import Control.Exception (displayException) @@ -56,6 +56,12 @@ data GovernanceCmdError GovernanceCmdMIRCertNotSupportedInConway | GovernanceCmdGenesisDelegationNotSupportedInConway | GovernanceDRepHashCheckError HashCheckError + | GovernanceCmdHashMismatchError + !(Hash DRepMetadata) + -- ^ Expected hash + !(Hash DRepMetadata) + -- ^ Actual hash + | GovernanceCmdFetchURLError !FetchURLError deriving Show instance Error GovernanceCmdError where @@ -119,5 +125,13 @@ instance Error GovernanceCmdError where "Genesis delegation is not supported in Conway era onwards." GovernanceDRepHashCheckError hashCheckError -> "Error while checking DRep metadata hash: " <> pretty (displayException hashCheckError) + GovernanceCmdHashMismatchError (DRepMetadataHash expectedHash) (DRepMetadataHash actualHash) -> + "Hashes do not match!" + <> "\nExpected:" + <+> pretty (show expectedHash) + <> "\n Actual:" + <+> pretty (show actualHash) + GovernanceCmdFetchURLError fetchErr -> + pretty (displayException fetchErr) where renderDecoderError = pretty . TL.toLazyText . B.build diff --git a/cardano-cli/test/cardano-cli-golden/Test/Golden/Governance/DRep.hs b/cardano-cli/test/cardano-cli-golden/Test/Golden/Governance/DRep.hs index 41e9482feb..3e1dcd4736 100644 --- a/cardano-cli/test/cardano-cli-golden/Test/Golden/Governance/DRep.hs +++ b/cardano-cli/test/cardano-cli-golden/Test/Golden/Governance/DRep.hs @@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-} + {- HLINT ignore "Use camelCase" -} module Test.Golden.Governance.DRep where @@ -16,8 +17,11 @@ import Numeric (showOct) import System.Posix.Files (fileMode, getFileStatus) #endif -import Test.Cardano.CLI.Util (FileSem, bracketSem, execCardanoCLI, newFileSem, - noteInputFile, noteTempFile, propertyOnce) +import GHC.IO.Exception (ExitCode (ExitFailure)) +import Test.Cardano.CLI.Hash (exampleAnchorDataHash, exampleAnchorDataIpfsHash, + exampleAnchorDataPathGolden, serveFilesWhile, tamperBase16Hash) +import Test.Cardano.CLI.Util (FileSem, bracketSem, execCardanoCLI, execDetailCardanoCLI, + newFileSem, noteInputFile, noteTempFile, propertyOnce) import Hedgehog import qualified Hedgehog as H @@ -32,7 +36,8 @@ drepRetirementCertSem = newFileSem "test/cardano-cli-golden/files/golden/governa -- | Semaphore protecting against locked file error, when running properties concurrently. drepRegistrationCertSem :: FileSem -drepRegistrationCertSem = newFileSem "test/cardano-cli-golden/files/golden/governance/drep/drep_registration_certificate.json" +drepRegistrationCertSem = + newFileSem "test/cardano-cli-golden/files/golden/governance/drep/drep_registration_certificate.json" {-# NOINLINE drepRegistrationCertSem #-} hprop_golden_governanceDRepKeyGen :: Property @@ -41,11 +46,17 @@ hprop_golden_governanceDRepKeyGen = verificationKeyFile <- H.noteTempFile tempDir "key-gen.vkey" signingKeyFile <- H.noteTempFile tempDir "key-gen.skey" - void $ execCardanoCLI - [ "conway", "governance", "drep", "key-gen" - , "--verification-key-file", verificationKeyFile - , "--signing-key-file", signingKeyFile - ] + void $ + execCardanoCLI + [ "conway" + , "governance" + , "drep" + , "key-gen" + , "--verification-key-file" + , verificationKeyFile + , "--signing-key-file" + , signingKeyFile + ] H.assertFileOccurences 1 "DRepVerificationKey_ed25519" verificationKeyFile H.assertFileOccurences 1 "DRepSigningKey_ed25519" signingKeyFile @@ -59,10 +70,10 @@ hprop_golden_governanceDRepKeyGen = vrfMode === "600" sgnMode === "600" - where - retrievePermissions path = withFrozenCallStack $ do - mode <- H.evalIO $ fileMode <$> getFileStatus path - pure $ showOct (mode .&. 0o777) "" -- we only need the 3 lowest octets here + where + retrievePermissions path = withFrozenCallStack $ do + mode <- H.evalIO $ fileMode <$> getFileStatus path + pure $ showOct (mode .&. 0o777) "" -- we only need the 3 lowest octets here #endif hprop_golden_governance_drep_id_bech32 :: Property @@ -72,12 +83,19 @@ hprop_golden_governance_drep_id_bech32 = idFile <- H.noteTempFile tempDir "drep.id.bech32" idGold <- H.note "test/cardano-cli-golden/files/golden/governance/drep/drep.id.bech32" - void $ execCardanoCLI - [ "conway", "governance", "drep", "id" - , "--drep-verification-key-file", vkeyFile - , "--output-format", "bech32" - , "--out-file", idFile - ] + void $ + execCardanoCLI + [ "conway" + , "governance" + , "drep" + , "id" + , "--drep-verification-key-file" + , vkeyFile + , "--output-format" + , "bech32" + , "--out-file" + , idFile + ] H.diffFileVsGoldenFile idFile idGold @@ -88,30 +106,46 @@ hprop_golden_governance_drep_id_hex = idFile <- H.noteTempFile tempDir "drep.id.hex" idGold <- H.note "test/cardano-cli-golden/files/golden/governance/drep/drep.id.hex" - void $ execCardanoCLI - [ "conway", "governance", "drep", "id" - , "--drep-verification-key-file", vkeyFile - , "--output-format", "hex" - , "--out-file", idFile - ] + void $ + execCardanoCLI + [ "conway" + , "governance" + , "drep" + , "id" + , "--drep-verification-key-file" + , vkeyFile + , "--output-format" + , "hex" + , "--out-file" + , idFile + ] H.diffFileVsGoldenFile idFile idGold hprop_golden_governance_drep_extended_key_signing :: Property hprop_golden_governance_drep_extended_key_signing = propertyOnce . H.moduleWorkspace "tmp" $ \tempDir -> do - skeyFile <- noteInputFile "test/cardano-cli-golden/files/input/governance/drep/extended-key-signing/drep.skey" - txBody <- noteInputFile "test/cardano-cli-golden/files/input/governance/drep/extended-key-signing/tx.body" + skeyFile <- + noteInputFile "test/cardano-cli-golden/files/input/governance/drep/extended-key-signing/drep.skey" + txBody <- + noteInputFile "test/cardano-cli-golden/files/input/governance/drep/extended-key-signing/tx.body" outFile <- H.noteTempFile tempDir "outFile" - outGold <- H.note "test/cardano-cli-golden/files/golden/governance/drep/extended-key-signing/tx.signed" - - H.noteShowM_ $ execCardanoCLI - [ "conway", "transaction", "sign" - , "--tx-body-file", txBody - , "--signing-key-file", skeyFile - , "--out-file", outFile - ] + outGold <- + H.note "test/cardano-cli-golden/files/golden/governance/drep/extended-key-signing/tx.signed" + + H.noteShowM_ $ + execCardanoCLI + [ "conway" + , "transaction" + , "sign" + , "--tx-body-file" + , txBody + , "--signing-key-file" + , skeyFile + , "--out-file" + , outFile + ] H.diffFileVsGoldenFile outFile outGold @@ -122,12 +156,19 @@ hprop_golden_governance_drep_retirement_certificate_vkey_file = certFile <- H.noteTempFile tempDir "drep.retirement.cert" H.noteShow_ drepRetirementCertSem - void $ execCardanoCLI - [ "conway", "governance", "drep", "retirement-certificate" - , "--drep-verification-key-file", drepVKeyFile - , "--deposit-amt", "1000000" - , "--out-file", certFile - ] + void $ + execCardanoCLI + [ "conway" + , "governance" + , "drep" + , "retirement-certificate" + , "--drep-verification-key-file" + , drepVKeyFile + , "--deposit-amt" + , "1000000" + , "--out-file" + , certFile + ] bracketSem drepRetirementCertSem $ H.diffFileVsGoldenFile certFile @@ -140,12 +181,19 @@ hprop_golden_governance_drep_retirement_certificate_id_hex = idFile <- H.readFile "test/cardano-cli-golden/files/input/drep.id.hex" - void $ execCardanoCLI - [ "conway", "governance", "drep", "retirement-certificate" - , "--drep-key-hash", idFile - , "--deposit-amt", "1000000" - , "--out-file", certFile - ] + void $ + execCardanoCLI + [ "conway" + , "governance" + , "drep" + , "retirement-certificate" + , "--drep-key-hash" + , idFile + , "--deposit-amt" + , "1000000" + , "--out-file" + , certFile + ] bracketSem drepRetirementCertSem $ H.diffFileVsGoldenFile certFile @@ -158,30 +206,45 @@ hprop_golden_governance_drep_retirement_certificate_id_bech32 = idFile <- H.readFile "test/cardano-cli-golden/files/input/drep.id.bech32" - void $ execCardanoCLI - [ "conway", "governance", "drep", "retirement-certificate" - , "--drep-key-hash", idFile - , "--deposit-amt", "1000000" - , "--out-file", certFile - ] + void $ + execCardanoCLI + [ "conway" + , "governance" + , "drep" + , "retirement-certificate" + , "--drep-key-hash" + , idFile + , "--deposit-amt" + , "1000000" + , "--out-file" + , certFile + ] bracketSem drepRetirementCertSem $ H.diffFileVsGoldenFile certFile hprop_golden_governance_drep_metadata_hash :: Property hprop_golden_governance_drep_metadata_hash = propertyOnce . H.moduleWorkspace "tmp" $ \tempDir -> do - goldenDRepMetadataHash <- H.note "test/cardano-cli-golden/files/golden/governance/drep/drep_metadata_hash" + goldenDRepMetadataHash <- + H.note "test/cardano-cli-golden/files/golden/governance/drep/drep_metadata_hash" drepMetadataFile <- noteTempFile tempDir "drep-metadata.json" - H.evalIO $ writeFile drepMetadataFile "{ \"Lorem\": \"ipsum\", \"dolor\": \"sit\", \"amet\": \"consectetur\" }" + H.evalIO $ + writeFile drepMetadataFile "{ \"Lorem\": \"ipsum\", \"dolor\": \"sit\", \"amet\": \"consectetur\" }" outputDRepMetadataHash <- H.noteTempFile tempDir "drep-metadata-hash.txt" - void $ execCardanoCLI - [ "conway", "governance", "drep","metadata-hash" - , "--drep-metadata-file", drepMetadataFile - , "--out-file", outputDRepMetadataHash - ] + void $ + execCardanoCLI + [ "conway" + , "governance" + , "drep" + , "metadata-hash" + , "--drep-metadata-file" + , drepMetadataFile + , "--out-file" + , outputDRepMetadataHash + ] H.diffFileVsGoldenFile outputDRepMetadataHash goldenDRepMetadataHash @@ -189,18 +252,25 @@ hprop_golden_governance_drep_metadata_hash = propertyOnce . H.moduleWorkspace "t -- @cabal test cardano-cli-golden --test-options '-p "/golden governance drep metadata hash cip119/"'@ hprop_golden_governance_drep_metadata_hash_cip119 :: Property hprop_golden_governance_drep_metadata_hash_cip119 = propertyOnce . H.moduleWorkspace "tmp" $ \tempDir -> do - goldenDRepMetadataHashCip119 <- H.note "test/cardano-cli-golden/files/golden/governance/drep/drep_metadata_hash_cip119" - - --Use jsonld file from test vector of CIP119 https://github.com/cardano-foundation/CIPs/blob/master/CIP-0119/test-vector.md + goldenDRepMetadataHashCip119 <- + H.note "test/cardano-cli-golden/files/golden/governance/drep/drep_metadata_hash_cip119" + + -- Use jsonld file from test vector of CIP119 https://github.com/cardano-foundation/CIPs/blob/master/CIP-0119/test-vector.md drepMetadataFile <- noteInputFile "test/cardano-cli-golden/files/input/governance/drep/drep.jsonld" outputDRepMetadataHashCip119 <- H.noteTempFile tempDir "drep-metadata-hash-cip119.txt" - void $ execCardanoCLI - [ "conway", "governance", "drep", "metadata-hash" - , "--drep-metadata-file", drepMetadataFile - , "--out-file", outputDRepMetadataHashCip119 - ] + void $ + execCardanoCLI + [ "conway" + , "governance" + , "drep" + , "metadata-hash" + , "--drep-metadata-file" + , drepMetadataFile + , "--out-file" + , outputDRepMetadataHashCip119 + ] H.diffFileVsGoldenFile outputDRepMetadataHashCip119 goldenDRepMetadataHashCip119 @@ -211,14 +281,23 @@ hprop_golden_governance_drep_registration_certificate_vkey_file = propertyOnce . outFile <- H.noteTempFile tempDir "drep-reg-cert.txt" - void $ execCardanoCLI - [ "conway", "governance", "drep", "registration-certificate" - , "--drep-verification-key-file", drepVKeyFile - , "--key-reg-deposit-amt", "0" - , "--drep-metadata-url", "dummy-url" - , "--drep-metadata-hash", "52e69500a92d80f2126c836a4903dc582006709f004cf7a28ed648f732dff8d2" - , "--out-file", outFile - ] + void $ + execCardanoCLI + [ "conway" + , "governance" + , "drep" + , "registration-certificate" + , "--drep-verification-key-file" + , drepVKeyFile + , "--key-reg-deposit-amt" + , "0" + , "--drep-metadata-url" + , "dummy-url" + , "--drep-metadata-hash" + , "52e69500a92d80f2126c836a4903dc582006709f004cf7a28ed648f732dff8d2" + , "--out-file" + , outFile + ] bracketSem drepRegistrationCertSem $ H.diffFileVsGoldenFile outFile @@ -230,14 +309,23 @@ hprop_golden_governance_drep_registration_certificate_id_hex = propertyOnce . H. outFile <- H.noteTempFile tempDir "drep-reg-cert.txt" - void $ execCardanoCLI - [ "conway", "governance", "drep", "registration-certificate" - , "--drep-key-hash", idFile - , "--key-reg-deposit-amt", "0" - , "--drep-metadata-url", "dummy-url" - , "--drep-metadata-hash", "52e69500a92d80f2126c836a4903dc582006709f004cf7a28ed648f732dff8d2" - , "--out-file", outFile - ] + void $ + execCardanoCLI + [ "conway" + , "governance" + , "drep" + , "registration-certificate" + , "--drep-key-hash" + , idFile + , "--key-reg-deposit-amt" + , "0" + , "--drep-metadata-url" + , "dummy-url" + , "--drep-metadata-hash" + , "52e69500a92d80f2126c836a4903dc582006709f004cf7a28ed648f732dff8d2" + , "--out-file" + , outFile + ] bracketSem drepRegistrationCertSem $ H.diffFileVsGoldenFile outFile @@ -249,32 +337,52 @@ hprop_golden_governance_drep_registration_certificate_id_bech32 = propertyOnce . outFile <- H.noteTempFile tempDir "drep-reg-cert.txt" - void $ execCardanoCLI - [ "conway", "governance", "drep", "registration-certificate" - , "--drep-key-hash", idFile - , "--key-reg-deposit-amt", "0" - , "--drep-metadata-url", "dummy-url" - , "--drep-metadata-hash", "52e69500a92d80f2126c836a4903dc582006709f004cf7a28ed648f732dff8d2" - , "--out-file", outFile - ] + void $ + execCardanoCLI + [ "conway" + , "governance" + , "drep" + , "registration-certificate" + , "--drep-key-hash" + , idFile + , "--key-reg-deposit-amt" + , "0" + , "--drep-metadata-url" + , "dummy-url" + , "--drep-metadata-hash" + , "52e69500a92d80f2126c836a4903dc582006709f004cf7a28ed648f732dff8d2" + , "--out-file" + , outFile + ] bracketSem drepRegistrationCertSem $ H.diffFileVsGoldenFile outFile hprop_golden_governance_drep_registration_certificate_script_hash :: Property hprop_golden_governance_drep_registration_certificate_script_hash = propertyOnce . H.moduleWorkspace "tmp" $ \tempDir -> do - goldenFile <- H.note "test/cardano-cli-golden/files/golden/governance/drep/drep_registration_certificate_script.json" + goldenFile <- + H.note + "test/cardano-cli-golden/files/golden/governance/drep/drep_registration_certificate_script.json" outFile <- H.noteTempFile tempDir "drep-reg-cert.txt" - void $ execCardanoCLI - [ "conway", "governance", "drep", "registration-certificate" - , "--drep-script-hash", "00000000000000000000000000000000000000000000000000000003" - , "--key-reg-deposit-amt", "0" - , "--drep-metadata-url", "dummy-url" - , "--drep-metadata-hash", "52e69500a92d80f2126c836a4903dc582006709f004cf7a28ed648f732dff8d2" - , "--out-file", outFile - ] + void $ + execCardanoCLI + [ "conway" + , "governance" + , "drep" + , "registration-certificate" + , "--drep-script-hash" + , "00000000000000000000000000000000000000000000000000000003" + , "--key-reg-deposit-amt" + , "0" + , "--drep-metadata-url" + , "dummy-url" + , "--drep-metadata-hash" + , "52e69500a92d80f2126c836a4903dc582006709f004cf7a28ed648f732dff8d2" + , "--out-file" + , outFile + ] H.diffFileVsGoldenFile outFile goldenFile @@ -283,34 +391,53 @@ hprop_golden_governance_drep_registration_certificate_script_hash = propertyOnce hprop_golden_governance_drep_update_certificate_vkey_file :: Property hprop_golden_governance_drep_update_certificate_vkey_file = propertyOnce . H.moduleWorkspace "tmp" $ \tempDir -> do drepVKeyFile <- noteInputFile "test/cardano-cli-golden/files/input/drep.vkey" - goldenFile <- H.note "test/cardano-cli-golden/files/golden/governance/drep/drep_update_certificate.json" + goldenFile <- + H.note "test/cardano-cli-golden/files/golden/governance/drep/drep_update_certificate.json" outFile <- H.noteTempFile tempDir "drep-upd-cert.txt" - void $ execCardanoCLI - [ "conway", "governance", "drep", "update-certificate" - , "--drep-verification-key-file", drepVKeyFile - , "--drep-metadata-url", "dummy-url" - , "--drep-metadata-hash", "52e69500a92d80f2126c836a4903dc582006709f004cf7a28ed648f732dff8d2" - , "--out-file", outFile - ] + void $ + execCardanoCLI + [ "conway" + , "governance" + , "drep" + , "update-certificate" + , "--drep-verification-key-file" + , drepVKeyFile + , "--drep-metadata-url" + , "dummy-url" + , "--drep-metadata-hash" + , "52e69500a92d80f2126c836a4903dc582006709f004cf7a28ed648f732dff8d2" + , "--out-file" + , outFile + ] H.diffFileVsGoldenFile outFile goldenFile - + -- | Execute me with: -- @cabal test cardano-cli-golden --test-options '-p "/golden governance drep update certificate script hash/"'@ hprop_golden_governance_drep_update_certificate_script_hash :: Property hprop_golden_governance_drep_update_certificate_script_hash = propertyOnce . H.moduleWorkspace "tmp" $ \tempDir -> do - goldenFile <- H.note "test/cardano-cli-golden/files/golden/governance/drep/drep_update_certificate_script_hash.json" + goldenFile <- + H.note + "test/cardano-cli-golden/files/golden/governance/drep/drep_update_certificate_script_hash.json" outFile <- H.noteTempFile tempDir "drep-upd-cert.txt" - void $ execCardanoCLI - [ "conway", "governance", "drep", "update-certificate" - , "--drep-script-hash", "8f33600845940d65bdbc7ea7a247a7997aa8558649128fa82c4c0468" - , "--drep-metadata-url", "https://raw.githubusercontent.com/cardano-foundation/CIPs/master/CIP-0119/examples/drep.jsonld" - , "--drep-metadata-hash", "fecc1773db89b45557d82e07719c275f6877a6cadfd2469f4dc5a7df5b38b4a4" - , "--out-file", outFile - ] + void $ + execCardanoCLI + [ "conway" + , "governance" + , "drep" + , "update-certificate" + , "--drep-script-hash" + , "8f33600845940d65bdbc7ea7a247a7997aa8558649128fa82c4c0468" + , "--drep-metadata-url" + , "https://raw.githubusercontent.com/cardano-foundation/CIPs/master/CIP-0119/examples/drep.jsonld" + , "--drep-metadata-hash" + , "fecc1773db89b45557d82e07719c275f6877a6cadfd2469f4dc5a7df5b38b4a4" + , "--out-file" + , outFile + ] H.diffFileVsGoldenFile outFile goldenFile @@ -319,14 +446,53 @@ hprop_golden_governance_drep_update_certificate_script_hash = propertyOnce . H.m hprop_golden_verification_key_drep :: Property hprop_golden_verification_key_drep = propertyOnce . H.moduleWorkspace "tmp" $ \tempDir -> do - skeyFile <- noteInputFile "test/cardano-cli-golden/files/input/governance/drep/extended-key-signing/drep.skey" + skeyFile <- + noteInputFile "test/cardano-cli-golden/files/input/governance/drep/extended-key-signing/drep.skey" vkeyFileOut <- noteTempFile tempDir "drep.extended.vkey" goldenFile <- H.note "test/cardano-cli-golden/files/golden/governance/drep/drep-extended.vkey.out" - H.noteShowM_ $ execCardanoCLI - [ "conway", "key", "verification-key" - , "--signing-key-file", skeyFile - , "--verification-key-file", vkeyFileOut - ] + H.noteShowM_ $ + execCardanoCLI + [ "conway" + , "key" + , "verification-key" + , "--signing-key-file" + , skeyFile + , "--verification-key-file" + , vkeyFileOut + ] H.diffFileVsGoldenFile vkeyFileOut goldenFile + +-- Execute me with: +-- @cabal test cardano-cli-test --test-options '-p "/drep metadata hash url wrong hash fails/"'@ +hprop_golden_drep_metadata_hash_url_wrong_hash_fails :: Property +hprop_golden_drep_metadata_hash_url_wrong_hash_fails = + propertyOnce $ do + -- We modify the hash slightly so that the hash check fails + alteredHash <- H.evalMaybe $ tamperBase16Hash exampleAnchorDataHash + let relativeUrl = [exampleAnchorDataIpfsHash] + + -- Create temporary HTTP server with files required by the call to `cardano-cli` + (exitCode, _, result) <- + serveFilesWhile + [ (relativeUrl, exampleAnchorDataPathGolden) + ] + ( \port -> do + execDetailCardanoCLI + [ "conway" + , "governance" + , "drep" + , "metadata-hash" + , "--drep-metadata-url" + , "http://127.0.0.1:" ++ show port ++ "/" ++ exampleAnchorDataIpfsHash + , "--expected-hash" + , alteredHash + ] + ) + + exitCode === ExitFailure 1 + + H.diffVsGoldenFile + result + "test/cardano-cli-golden/files/golden/governance/drep/drep_metadata_hash_url_wrong_hash_fails.out" diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/governance/drep/drep_metadata_hash_url_wrong_hash_fails.out b/cardano-cli/test/cardano-cli-golden/files/golden/governance/drep/drep_metadata_hash_url_wrong_hash_fails.out new file mode 100644 index 0000000000..2021fd252f --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/files/golden/governance/drep/drep_metadata_hash_url_wrong_hash_fails.out @@ -0,0 +1,3 @@ +Command failed: governance drep metadata-hash Error: Hashes do not match! +Expected: "ee38a4f5b8b9d8372386cc923bad19d1a0662298cf355bbe947e5eedf127fa9c" + Actual: "de38a4f5b8b9d8372386cc923bad19d1a0662298cf355bbe947e5eedf127fa9c" diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/help.cli b/cardano-cli/test/cardano-cli-golden/files/golden/help.cli index 4e133a9d60..ff8632d071 100644 --- a/cardano-cli/test/cardano-cli-golden/files/golden/help.cli +++ b/cardano-cli/test/cardano-cli-golden/files/golden/help.cli @@ -6861,10 +6861,16 @@ Usage: cardano-cli conway governance drep update-certificate Create a DRep update certificate. -Usage: cardano-cli conway governance drep metadata-hash --drep-metadata-file FILEPATH - [--out-file FILEPATH] +Usage: cardano-cli conway governance drep metadata-hash + ( --drep-metadata-file FILEPATH + | --drep-metadata-url TEXT + ) + [ --expected-hash HASH + | --out-file FILEPATH + ] - Calculate the hash of a metadata file. + Calculate the hash of a metadata file, optionally checking the obtained hash + against an expected value. Usage: cardano-cli conway governance vote (create | view) @@ -8847,10 +8853,16 @@ Usage: cardano-cli latest governance drep update-certificate Create a DRep update certificate. -Usage: cardano-cli latest governance drep metadata-hash --drep-metadata-file FILEPATH - [--out-file FILEPATH] +Usage: cardano-cli latest governance drep metadata-hash + ( --drep-metadata-file FILEPATH + | --drep-metadata-url TEXT + ) + [ --expected-hash HASH + | --out-file FILEPATH + ] - Calculate the hash of a metadata file. + Calculate the hash of a metadata file, optionally checking the obtained hash + against an expected value. Usage: cardano-cli latest governance vote (create | view) diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_drep.cli b/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_drep.cli index 6d23ec55ac..ef5f334fa9 100644 --- a/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_drep.cli +++ b/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_drep.cli @@ -19,4 +19,5 @@ Available commands: registration-certificate Create a registration certificate. retirement-certificate Create a DRep retirement certificate. update-certificate Create a DRep update certificate. - metadata-hash Calculate the hash of a metadata file. + metadata-hash Calculate the hash of a metadata file, optionally + checking the obtained hash against an expected value. diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_drep_metadata-hash.cli b/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_drep_metadata-hash.cli index b19fa03019..cf1c1d8099 100644 --- a/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_drep_metadata-hash.cli +++ b/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_drep_metadata-hash.cli @@ -1,10 +1,20 @@ -Usage: cardano-cli conway governance drep metadata-hash --drep-metadata-file FILEPATH - [--out-file FILEPATH] +Usage: cardano-cli conway governance drep metadata-hash + ( --drep-metadata-file FILEPATH + | --drep-metadata-url TEXT + ) + [ --expected-hash HASH + | --out-file FILEPATH + ] - Calculate the hash of a metadata file. + Calculate the hash of a metadata file, optionally checking the obtained hash + against an expected value. Available options: --drep-metadata-file FILEPATH JSON Metadata file to hash. - --out-file FILEPATH Optional output file. Default is to write to stdout. + --drep-metadata-url TEXT URL pointing to the JSON Metadata file to hash. + --expected-hash HASH Expected hash for the DRep metadata, for verification + purposes. If provided, the hash of the DRep metadata + is compared to this value. + --out-file FILEPATH The output file. -h,--help Show this help text diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/help/latest_governance_drep.cli b/cardano-cli/test/cardano-cli-golden/files/golden/help/latest_governance_drep.cli index c528ca5510..aa51969226 100644 --- a/cardano-cli/test/cardano-cli-golden/files/golden/help/latest_governance_drep.cli +++ b/cardano-cli/test/cardano-cli-golden/files/golden/help/latest_governance_drep.cli @@ -19,4 +19,5 @@ Available commands: registration-certificate Create a registration certificate. retirement-certificate Create a DRep retirement certificate. update-certificate Create a DRep update certificate. - metadata-hash Calculate the hash of a metadata file. + metadata-hash Calculate the hash of a metadata file, optionally + checking the obtained hash against an expected value. diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/help/latest_governance_drep_metadata-hash.cli b/cardano-cli/test/cardano-cli-golden/files/golden/help/latest_governance_drep_metadata-hash.cli index 8244533c50..30264f2d17 100644 --- a/cardano-cli/test/cardano-cli-golden/files/golden/help/latest_governance_drep_metadata-hash.cli +++ b/cardano-cli/test/cardano-cli-golden/files/golden/help/latest_governance_drep_metadata-hash.cli @@ -1,10 +1,20 @@ -Usage: cardano-cli latest governance drep metadata-hash --drep-metadata-file FILEPATH - [--out-file FILEPATH] +Usage: cardano-cli latest governance drep metadata-hash + ( --drep-metadata-file FILEPATH + | --drep-metadata-url TEXT + ) + [ --expected-hash HASH + | --out-file FILEPATH + ] - Calculate the hash of a metadata file. + Calculate the hash of a metadata file, optionally checking the obtained hash + against an expected value. Available options: --drep-metadata-file FILEPATH JSON Metadata file to hash. - --out-file FILEPATH Optional output file. Default is to write to stdout. + --drep-metadata-url TEXT URL pointing to the JSON Metadata file to hash. + --expected-hash HASH Expected hash for the DRep metadata, for verification + purposes. If provided, the hash of the DRep metadata + is compared to this value. + --out-file FILEPATH The output file. -h,--help Show this help text diff --git a/cardano-cli/test/cardano-cli-test/Test/Cli/DRepMetadata.hs b/cardano-cli/test/cardano-cli-test/Test/Cli/DRepMetadata.hs new file mode 100644 index 0000000000..99655ab383 --- /dev/null +++ b/cardano-cli/test/cardano-cli-test/Test/Cli/DRepMetadata.hs @@ -0,0 +1,63 @@ +{-# LANGUAGE FlexibleContexts #-} + +module Test.Cli.DRepMetadata where + +import Cardano.Api (MonadIO) + +import Control.Monad (void) +import Control.Monad.Catch (MonadCatch) +import Control.Monad.Trans.Control (MonadBaseControl) + +import Test.Cardano.CLI.Hash (exampleAnchorDataHash, exampleAnchorDataIpfsHash, + exampleAnchorDataPathTest, serveFilesWhile, tamperBase16Hash) +import Test.Cardano.CLI.Util (execCardanoCLIWithEnvVars, expectFailure, propertyOnce) + +import Hedgehog (Property) +import qualified Hedgehog as H +import Hedgehog.Internal.Property (MonadTest) + +-- Execute me with: +-- @cabal test cardano-cli-test --test-options '-p "/drep metadata hash url wrong hash fails/"'@ +hprop_drep_metadata_hash_url_wrong_hash_fails :: Property +hprop_drep_metadata_hash_url_wrong_hash_fails = + propertyOnce . expectFailure $ do + -- We modify the hash slightly so that the hash check fails + alteredHash <- H.evalMaybe $ tamperBase16Hash exampleAnchorDataHash + -- We run the test with the modified hash + baseDrepMetadataHashUrl alteredHash + +-- Execute me with: +-- @cabal test cardano-cli-test --test-options '-p "/drep metadata hash url correct hash/"'@ +hprop_drep_metadata_hash_url_correct_hash :: Property +hprop_drep_metadata_hash_url_correct_hash = + propertyOnce $ baseDrepMetadataHashUrl exampleAnchorDataHash + +baseDrepMetadataHashUrl + :: (MonadBaseControl IO m, MonadTest m, MonadIO m, MonadCatch m) + => String + -- ^ The hash to check against. Changing this value allows us to test the + -- behavior of the command both when the hash is correct and when it is incorrect + -- reusing the same code. + -> m () +baseDrepMetadataHashUrl hash = do + let relativeUrl = ["ipfs", exampleAnchorDataIpfsHash] + + -- Create temporary HTTP server with files required by the call to `cardano-cli` + -- In this case, the server emulates an IPFS gateway + serveFilesWhile + [ (relativeUrl, exampleAnchorDataPathTest) + ] + ( \port -> do + void $ + execCardanoCLIWithEnvVars + [("IPFS_GATEWAY_URI", "http://localhost:" ++ show port ++ "/")] + [ "conway" + , "governance" + , "drep" + , "metadata-hash" + , "--drep-metadata-url" + , "ipfs://" ++ exampleAnchorDataIpfsHash + , "--expected-hash" + , hash + ] + )