diff --git a/cardano-cli/cardano-cli.cabal b/cardano-cli/cardano-cli.cabal index 6d1c830236..4d9e9f6f75 100644 --- a/cardano-cli/cardano-cli.cabal +++ b/cardano-cli/cardano-cli.cabal @@ -365,6 +365,7 @@ test-suite cardano-cli-golden Test.Golden.Governance.Action Test.Golden.Governance.Committee Test.Golden.Governance.DRep + Test.Golden.Governance.Vote Test.Golden.Help Test.Golden.Key.NonExtendedKey Test.Golden.Shelley.Address.Build diff --git a/cardano-cli/src/Cardano/CLI/EraBased/Commands/Governance/Vote.hs b/cardano-cli/src/Cardano/CLI/EraBased/Commands/Governance/Vote.hs index ea0f3c8e27..b8ecf4e68e 100644 --- a/cardano-cli/src/Cardano/CLI/EraBased/Commands/Governance/Vote.hs +++ b/cardano-cli/src/Cardano/CLI/EraBased/Commands/Governance/Vote.hs @@ -3,17 +3,31 @@ module Cardano.CLI.EraBased.Commands.Governance.Vote ( GovernanceVoteCmds(..) + , AnyVoteViewCmd(..) , renderGovernanceVoteCmds ) where +import Cardano.Api.Shelley + import Cardano.CLI.Types.Governance import Data.Text (Text) -newtype GovernanceVoteCmds era +data GovernanceVoteCmds era = GovernanceVoteCreateCmd AnyVote + | GovernanceVoteViewCmd + (AnyVoteViewCmd era) + +data AnyVoteViewCmd era + = AnyVoteViewCmd + { governanceVoteViewCmdYamlOutput :: Bool + , governanceVoteViewCmdEra :: ConwayEraOnwards era + , governanceVoteViewCmdVoteFile :: VoteFile In + , governanceVoteViewCmdOutputFile :: Maybe (File () Out) + } + renderGovernanceVoteCmds :: () => GovernanceVoteCmds era @@ -21,3 +35,5 @@ renderGovernanceVoteCmds :: () renderGovernanceVoteCmds = \case GovernanceVoteCreateCmd {} -> "governance vote create" + GovernanceVoteViewCmd {} -> + "governance vote view" diff --git a/cardano-cli/src/Cardano/CLI/EraBased/Options/Governance/Vote.hs b/cardano-cli/src/Cardano/CLI/EraBased/Options/Governance/Vote.hs index 4c286afbb4..1212a8937d 100644 --- a/cardano-cli/src/Cardano/CLI/EraBased/Options/Governance/Vote.hs +++ b/cardano-cli/src/Cardano/CLI/EraBased/Options/Governance/Vote.hs @@ -20,12 +20,9 @@ pGovernanceVoteCmds :: () -> Maybe (Parser (GovernanceVoteCmds era)) pGovernanceVoteCmds era = subInfoParser "vote" - ( Opt.progDesc - $ mconcat - [ "Vote commands." - ] - ) - [ pGovernanceVoteCreateCmd era + (Opt.progDesc "Vote commands.") + [ pGovernanceVoteCreateCmd era, + pGovernanceVoteViewCmd era ] pGovernanceVoteCreateCmd :: () @@ -54,3 +51,29 @@ pAnyVotingStakeVerificationKeyOrHashOrFile = asum [ AnyDRepVerificationKeyOrHashOrFile <$> pDRepVerificationKeyOrHashOrFile , AnyStakePoolVerificationKeyOrHashOrFile <$> pStakePoolVerificationKeyOrHashOrFile Nothing ] + +pGovernanceVoteViewCmd :: () + => CardanoEra era + -> Maybe (Parser (GovernanceVoteCmds era)) +pGovernanceVoteViewCmd era = do + w <- forEraMaybeEon era + pure + $ subParser "view" + $ Opt.info + (GovernanceVoteViewCmd <$> pAnyVoteViewCmd w) + $ Opt.progDesc "Vote viewing." + +pAnyVoteViewCmd :: ConwayEraOnwards era -> Parser (AnyVoteViewCmd era) +pAnyVoteViewCmd cOnwards = + AnyVoteViewCmd + <$> pYamlOutput + <*> pure cOnwards + <*> pFileInDirection "vote-file" "Input filepath of the vote." + <*> pMaybeOutputFile + where + pYamlOutput :: Parser Bool + pYamlOutput = + Opt.switch + ( Opt.long "yaml" + <> Opt.help "Output vote in YAML format (and not JSON)." + ) diff --git a/cardano-cli/src/Cardano/CLI/EraBased/Run/Governance/Vote.hs b/cardano-cli/src/Cardano/CLI/EraBased/Run/Governance/Vote.hs index e6c0db0b93..9148fc001a 100644 --- a/cardano-cli/src/Cardano/CLI/EraBased/Run/Governance/Vote.hs +++ b/cardano-cli/src/Cardano/CLI/EraBased/Run/Governance/Vote.hs @@ -13,16 +13,19 @@ import qualified Cardano.Api.Ledger as Ledger import Cardano.Api.Shelley import Cardano.CLI.EraBased.Commands.Governance.Vote +import Cardano.CLI.Read (readVotingProceduresFile) import Cardano.CLI.Types.Errors.CmdError import Cardano.CLI.Types.Errors.GovernanceVoteCmdError import Cardano.CLI.Types.Governance import Cardano.CLI.Types.Key import Cardano.Ledger.Keys (coerceKeyRole) -import Control.Monad.Except +import Control.Monad.Trans.Except import Control.Monad.Trans.Except.Extra +import Data.Aeson.Encode.Pretty import Data.Bifunctor import Data.Function +import qualified Data.Yaml.Pretty as Yaml runGovernanceVoteCmds :: () => GovernanceVoteCmds era @@ -31,6 +34,9 @@ runGovernanceVoteCmds = \case GovernanceVoteCreateCmd anyVote -> runGovernanceVoteCreateCmd anyVote & firstExceptT CmdGovernanceVoteError + GovernanceVoteViewCmd (AnyVoteViewCmd printYaml w voteFile mOutFile) -> + runGovernanceVoteViewCmd printYaml w voteFile mOutFile + & firstExceptT CmdGovernanceVoteError runGovernanceVoteCreateCmd :: AnyVote @@ -41,7 +47,7 @@ runGovernanceVoteCreateCmd (ConwayOnwardsVote cOnwards voteChoice (govActionTxId shelleyBasedEraConstraints sbe $ do case voteStakeCred of AnyDRepVerificationKeyOrHashOrFile stake -> do - DRepKeyHash h <- firstExceptT GovernanceVoteCmdReadError + DRepKeyHash h <- firstExceptT GovernanceVoteCmdReadVerificationKeyError . newExceptT $ readVerificationKeyOrHashOrTextEnvFile AsDRepKey stake let vStakeCred = StakeCredentialByKey . StakeKeyHash $ coerceKeyRole h @@ -53,7 +59,7 @@ runGovernanceVoteCreateCmd (ConwayOnwardsVote cOnwards voteChoice (govActionTxId firstExceptT GovernanceVoteCmdWriteError . newExceptT $ writeFileTextEnvelope oFp Nothing votingProcedures AnyStakePoolVerificationKeyOrHashOrFile stake -> do - h <- firstExceptT GovernanceVoteCmdReadError + h <- firstExceptT GovernanceVoteCmdReadVerificationKeyError . newExceptT $ readVerificationKeyOrHashOrTextEnvFile AsStakePoolKey stake let voter = Ledger.StakePoolVoter (unStakePoolKeyHash h) @@ -63,7 +69,7 @@ runGovernanceVoteCreateCmd (ConwayOnwardsVote cOnwards voteChoice (govActionTxId firstExceptT GovernanceVoteCmdWriteError . newExceptT $ writeFileTextEnvelope oFp Nothing votingProcedures AnyCommitteeHotVerificationKeyOrHashOrFile stake -> do - CommitteeHotKeyHash h <- firstExceptT GovernanceVoteCmdReadError + CommitteeHotKeyHash h <- firstExceptT GovernanceVoteCmdReadVerificationKeyError . newExceptT $ readVerificationKeyOrHashOrTextEnvFile AsCommitteeHotKey stake let vStakeCred = StakeCredentialByKey . StakeKeyHash $ coerceKeyRole h votingCred <- hoistEither $ first GovernanceVoteCmdCredentialDecodeError $ toVotingCredential cOnwards vStakeCred @@ -72,3 +78,23 @@ runGovernanceVoteCreateCmd (ConwayOnwardsVote cOnwards voteChoice (govActionTxId voteProcedure = createVotingProcedure cOnwards voteChoice Nothing votingProcedures = singletonVotingProcedures cOnwards voter govActIdentifier (unVotingProcedure voteProcedure) firstExceptT GovernanceVoteCmdWriteError . newExceptT $ writeFileTextEnvelope oFp Nothing votingProcedures + +runGovernanceVoteViewCmd + :: Bool + -> ConwayEraOnwards era + -> VoteFile In + -> Maybe (File () Out) + -> ExceptT GovernanceVoteCmdError IO () +runGovernanceVoteViewCmd outputYaml w fp mOutFile = do + let sbe = conwayEraOnwardsToShelleyBasedEra w + + shelleyBasedEraConstraints sbe $ do + voteProcedures <- firstExceptT GovernanceVoteCmdReadVoteFileError . newExceptT $ + readVotingProceduresFile w fp + firstExceptT GovernanceVoteCmdWriteError . + newExceptT . + (if outputYaml + then writeByteStringOutput mOutFile . Yaml.encodePretty (Yaml.setConfCompare compare Yaml.defConfig) + else writeLazyByteStringOutput mOutFile . encodePretty' (defConfig {confCompare = compare})) . + unVotingProcedures $ + voteProcedures diff --git a/cardano-cli/src/Cardano/CLI/Read.hs b/cardano-cli/src/Cardano/CLI/Read.hs index 52c5b8be1e..0b5c3bf0df 100644 --- a/cardano-cli/src/Cardano/CLI/Read.hs +++ b/cardano-cli/src/Cardano/CLI/Read.hs @@ -757,11 +757,14 @@ readRequiredSigner (RequiredSignerSkeyFile skFile) = do getHash (ShelleyNormalSigningKey sk) = verificationKeyHash . getVerificationKey $ PaymentSigningKey sk -data VoteError +newtype VoteError = VoteErrorFile (FileError TextEnvelopeError) - | VotesNotSupportedInEra AnyCardanoEra deriving Show +instance Error VoteError where + displayError = \case + VoteErrorFile e -> displayError e + readVotingProceduresFiles :: () => ConwayEraOnwards era -> [VoteFile In] diff --git a/cardano-cli/src/Cardano/CLI/Types/Errors/GovernanceVoteCmdError.hs b/cardano-cli/src/Cardano/CLI/Types/Errors/GovernanceVoteCmdError.hs index ce0a6aa757..0160d568af 100644 --- a/cardano-cli/src/Cardano/CLI/Types/Errors/GovernanceVoteCmdError.hs +++ b/cardano-cli/src/Cardano/CLI/Types/Errors/GovernanceVoteCmdError.hs @@ -8,20 +8,25 @@ import Cardano.Api.Shelley import Cardano.Binary (DecoderError) +import Cardano.CLI.Read (VoteError) + import qualified Data.Text.Lazy as TL import qualified Data.Text.Lazy.Builder as TL import qualified Formatting.Buildable as B data GovernanceVoteCmdError - = GovernanceVoteCmdReadError !(FileError InputDecodeError) + = GovernanceVoteCmdReadVerificationKeyError !(FileError InputDecodeError) + | GovernanceVoteCmdReadVoteFileError !VoteError | GovernanceVoteCmdCredentialDecodeError !DecoderError | GovernanceVoteCmdWriteError !(FileError ()) deriving Show instance Error GovernanceVoteCmdError where displayError = \case - GovernanceVoteCmdReadError e -> + GovernanceVoteCmdReadVerificationKeyError e -> "Cannot read verification key: " <> displayError e + GovernanceVoteCmdReadVoteFileError e -> + "Cannot read vote file: " <> displayError e GovernanceVoteCmdCredentialDecodeError e -> "Cannot decode voting credential: " <> renderDecoderError e GovernanceVoteCmdWriteError e -> diff --git a/cardano-cli/test/cardano-cli-golden/Test/Golden/ErrorsSpec.hs b/cardano-cli/test/cardano-cli-golden/Test/Golden/ErrorsSpec.hs index d23d19ce63..9f86430822 100644 --- a/cardano-cli/test/cardano-cli-golden/Test/Golden/ErrorsSpec.hs +++ b/cardano-cli/test/cardano-cli-golden/Test/Golden/ErrorsSpec.hs @@ -146,8 +146,10 @@ test_VoteReadError = [ ("GovernanceVoteCmdCredentialDecodeError" , GovernanceVoteCmdCredentialDecodeError $ DecoderErrorCustom "" "") - , ("GovernanceVoteCmdReadError" - , GovernanceVoteCmdReadError $ FileError "path/file.txt" InputInvalidError) + , ("GovernanceVoteCmdReadVerificationKeyError" + , GovernanceVoteCmdReadVerificationKeyError $ FileError "path/file.txt" InputInvalidError) + , ("GovernanceVoteCmdReadVoteFileError" + , GovernanceVoteCmdReadVoteFileError $ VoteErrorFile $ FileError "path/file.txt" $ TextEnvelopeAesonDecodeError "some error description") , ("GovernanceVoteCmdWriteError" , GovernanceVoteCmdWriteError $ FileError "path/file.txt" ()) ] diff --git a/cardano-cli/test/cardano-cli-golden/Test/Golden/Governance/Vote.hs b/cardano-cli/test/cardano-cli-golden/Test/Golden/Governance/Vote.hs new file mode 100644 index 0000000000..a8ca4ad966 --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/Test/Golden/Governance/Vote.hs @@ -0,0 +1,68 @@ +{- HLINT ignore "Use camelCase" -} + +module Test.Golden.Governance.Vote where + +import Control.Monad (void) + +import Test.Cardano.CLI.Util (execCardanoCLI, noteInputFile, propertyOnce) + +import Hedgehog +import qualified Hedgehog.Extras.Test.Base as H +import qualified Hedgehog.Extras.Test.Golden as H + +hprop_golden_governance_governance_vote_create :: Property +hprop_golden_governance_governance_vote_create = + propertyOnce . H.moduleWorkspace "tmp" $ \tempDir -> do + vkeyFile <- noteInputFile "test/cardano-cli-golden/files/input/drep.vkey" + voteFile <- H.noteTempFile tempDir "vote" + voteGold <- H.note "test/cardano-cli-golden/files/golden/governance/vote/vote" + + void $ execCardanoCLI + [ "conway", "governance", "vote", "create" + , "--yes" + , "--governance-action-tx-id", "b1015258a99351c143a7a40b7b58f033ace10e3cc09c67780ed5b2b0992aa60a" + , "--governance-action-index", "5" + , "--drep-verification-key-file", vkeyFile + , "--out-file", voteFile + ] + + H.diffFileVsGoldenFile voteFile voteGold + +hprop_golden_governance_governance_vote_view_json_stdout :: Property +hprop_golden_governance_governance_vote_view_json_stdout = + propertyOnce $ do + voteFile <- noteInputFile "test/cardano-cli-golden/files/golden/governance/vote/vote" + voteViewGold <- H.note "test/cardano-cli-golden/files/golden/governance/vote/voteViewJSON" + voteView <- execCardanoCLI + [ "conway", "governance", "vote", "view" + , "--vote-file", voteFile + ] + + H.diffVsGoldenFile voteView voteViewGold + +hprop_golden_governance_governance_vote_view_json_outfile :: Property +hprop_golden_governance_governance_vote_view_json_outfile = + propertyOnce . H.moduleWorkspace "tmp" $ \tempDir -> do + voteFile <- noteInputFile "test/cardano-cli-golden/files/golden/governance/vote/vote" + voteViewFile <- H.noteTempFile tempDir "voteView" + voteViewGold <- H.note "test/cardano-cli-golden/files/golden/governance/vote/voteViewJSON" + void $ execCardanoCLI + [ "conway", "governance", "vote", "view" + , "--vote-file", voteFile + , "--out-file", voteViewFile + ] + + H.diffFileVsGoldenFile voteViewFile voteViewGold + +hprop_golden_governance_governance_vote_view_yaml :: Property +hprop_golden_governance_governance_vote_view_yaml = + propertyOnce $ do + voteFile <- noteInputFile "test/cardano-cli-golden/files/golden/governance/vote/vote" + voteViewGold <- H.note "test/cardano-cli-golden/files/golden/governance/vote/voteViewYAML" + voteView <- execCardanoCLI + [ "conway", "governance", "vote", "view" + , "--yaml" + , "--vote-file", voteFile + ] + + H.diffVsGoldenFile voteView voteViewGold diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/errors/Cardano.CLI.Types.Errors.GovernanceVoteCmdError.GovernanceVoteCmdError/GovernanceVoteCmdReadError.txt b/cardano-cli/test/cardano-cli-golden/files/golden/errors/Cardano.CLI.Types.Errors.GovernanceVoteCmdError.GovernanceVoteCmdError/GovernanceVoteCmdReadVerificationKeyError.txt similarity index 100% rename from cardano-cli/test/cardano-cli-golden/files/golden/errors/Cardano.CLI.Types.Errors.GovernanceVoteCmdError.GovernanceVoteCmdError/GovernanceVoteCmdReadError.txt rename to cardano-cli/test/cardano-cli-golden/files/golden/errors/Cardano.CLI.Types.Errors.GovernanceVoteCmdError.GovernanceVoteCmdError/GovernanceVoteCmdReadVerificationKeyError.txt diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/errors/Cardano.CLI.Types.Errors.GovernanceVoteCmdError.GovernanceVoteCmdError/GovernanceVoteCmdReadVoteFileError.txt b/cardano-cli/test/cardano-cli-golden/files/golden/errors/Cardano.CLI.Types.Errors.GovernanceVoteCmdError.GovernanceVoteCmdError/GovernanceVoteCmdReadVoteFileError.txt new file mode 100644 index 0000000000..4c4805607b --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/files/golden/errors/Cardano.CLI.Types.Errors.GovernanceVoteCmdError.GovernanceVoteCmdError/GovernanceVoteCmdReadVoteFileError.txt @@ -0,0 +1 @@ +Cannot read vote file: path/file.txt: TextEnvelope aeson decode error: some error description diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/governance/vote/vote b/cardano-cli/test/cardano-cli-golden/files/golden/governance/vote/vote new file mode 100644 index 0000000000..b97d5e22c1 --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/files/golden/governance/vote/vote @@ -0,0 +1,5 @@ +{ + "type": "Governance voting procedures", + "description": "", + "cborHex": "a18202581ceb09d5556a8bce421074e394d02c79ced96741657b4cf7ca8995294da1825820b1015258a99351c143a7a40b7b58f033ace10e3cc09c67780ed5b2b0992aa60a058201f6" +} diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/governance/vote/voteViewJSON b/cardano-cli/test/cardano-cli-golden/files/golden/governance/vote/voteViewJSON new file mode 100644 index 0000000000..df032476a6 --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/files/golden/governance/vote/voteViewJSON @@ -0,0 +1,8 @@ +{ + "drep-keyHash-eb09d5556a8bce421074e394d02c79ced96741657b4cf7ca8995294d": { + "b1015258a99351c143a7a40b7b58f033ace10e3cc09c67780ed5b2b0992aa60a#5": { + "anchor": null, + "decision": "VoteYes" + } + } +} diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/governance/vote/voteViewYAML b/cardano-cli/test/cardano-cli-golden/files/golden/governance/vote/voteViewYAML new file mode 100644 index 0000000000..5086693856 --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/files/golden/governance/vote/voteViewYAML @@ -0,0 +1,4 @@ +drep-keyHash-eb09d5556a8bce421074e394d02c79ced96741657b4cf7ca8995294d: + b1015258a99351c143a7a40b7b58f033ace10e3cc09c67780ed5b2b0992aa60a#5: + anchor: null + decision: VoteYes 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 83bec9c30c..70f77e3cd8 100644 --- a/cardano-cli/test/cardano-cli-golden/files/golden/help.cli +++ b/cardano-cli/test/cardano-cli-golden/files/golden/help.cli @@ -6525,7 +6525,7 @@ Usage: cardano-cli conway governance drep registration-certificate Create a registration certificate. -Usage: cardano-cli conway governance vote create +Usage: cardano-cli conway governance vote (create | view) Vote commands. @@ -6543,6 +6543,12 @@ Usage: cardano-cli conway governance vote create (--yes | --no | --abstain) Vote creation. +Usage: cardano-cli conway governance vote view [--yaml] + --vote-file FILE + [--out-file FILE] + + Vote viewing. + Usage: cardano-cli conway node ( key-gen | key-gen-KES diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_vote.cli b/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_vote.cli new file mode 100644 index 0000000000..1447f62658 --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_vote.cli @@ -0,0 +1,10 @@ +Usage: cardano-cli conway governance vote (create | view) + + Vote commands. + +Available options: + -h,--help Show this help text + +Available commands: + create Vote creation. + view Vote viewing. diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_vote_view.cli b/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_vote_view.cli new file mode 100644 index 0000000000..35b4b36607 --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_vote_view.cli @@ -0,0 +1,11 @@ +Usage: cardano-cli conway governance vote view [--yaml] + --vote-file FILE + [--out-file FILE] + + Vote viewing. + +Available options: + --yaml Output vote in YAML format (and not JSON). + --vote-file FILE Input filepath of the vote. + --out-file FILE Optional output file. Default is to write to stdout. + -h,--help Show this help text