Skip to content

Commit

Permalink
create-poll, answer-poll, verify-poll: move to 'babbage governance' b…
Browse files Browse the repository at this point in the history
…lock
  • Loading branch information
smelc committed Oct 2, 2023
1 parent 374d2d5 commit a20579b
Show file tree
Hide file tree
Showing 10 changed files with 286 additions and 191 deletions.
3 changes: 3 additions & 0 deletions cardano-cli/cardano-cli.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ library
Cardano.CLI.EraBased.Commands.Governance.Actions
Cardano.CLI.EraBased.Commands.Governance.Committee
Cardano.CLI.EraBased.Commands.Governance.DRep
Cardano.CLI.EraBased.Commands.Governance.Poll
Cardano.CLI.EraBased.Commands.Governance.Query
Cardano.CLI.EraBased.Commands.Governance.Vote
Cardano.CLI.EraBased.Commands.Key
Expand All @@ -91,6 +92,7 @@ library
Cardano.CLI.EraBased.Options.Governance.Actions
Cardano.CLI.EraBased.Options.Governance.Committee
Cardano.CLI.EraBased.Options.Governance.DRep
Cardano.CLI.EraBased.Options.Governance.Poll
Cardano.CLI.EraBased.Options.Governance.Query
Cardano.CLI.EraBased.Options.Governance.Vote
Cardano.CLI.EraBased.Options.Key
Expand All @@ -108,6 +110,7 @@ library
Cardano.CLI.EraBased.Run.Governance.Actions
Cardano.CLI.EraBased.Run.Governance.Committee
Cardano.CLI.EraBased.Run.Governance.DRep
Cardano.CLI.EraBased.Run.Governance.Poll
Cardano.CLI.EraBased.Run.Governance.Query
Cardano.CLI.EraBased.Run.Governance.Vote
Cardano.CLI.EraBased.Run.Key
Expand Down
5 changes: 5 additions & 0 deletions cardano-cli/src/Cardano/CLI/EraBased/Commands/Governance.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Cardano.CLI.EraBased.Commands.Governance.Actions
import Cardano.CLI.EraBased.Commands.Governance.Committee
import Cardano.CLI.EraBased.Commands.Governance.DRep
import Cardano.CLI.EraBased.Commands.Governance.Query
import Cardano.CLI.EraBased.Commands.Governance.Poll
import Cardano.CLI.EraBased.Commands.Governance.Vote
import Cardano.CLI.Types.Common

Expand All @@ -36,6 +37,8 @@ data GovernanceCmds era
(GovernanceCommitteeCmds era)
| GovernanceDRepCmds
(GovernanceDRepCmds era)
| GovernancePollCmds
(GovernancePollCmds era)
| GovernanceVoteCmds
(GovernanceVoteCmds era)
| GovernanceQueryCmds
Expand All @@ -55,6 +58,8 @@ renderGovernanceCmds = \case
renderGovernanceCommitteeCmds cmds
GovernanceDRepCmds cmds ->
renderGovernanceDRepCmds cmds
GovernancePollCmds cmds ->
renderGovernancePollCmds cmds
GovernanceVoteCmds cmds ->
renderGovernanceVoteCmds cmds
GovernanceQueryCmds cmds ->
Expand Down
37 changes: 37 additions & 0 deletions cardano-cli/src/Cardano/CLI/EraBased/Commands/Governance/Poll.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}

module Cardano.CLI.EraBased.Commands.Governance.Poll
( GovernancePollCmds(..) , renderGovernancePollCmds) where

import Cardano.Api
import Cardano.Api.Shelley

import Data.Text (Text)

data GovernancePollCmds era
= GovernanceCreatePoll -- ^ Create a SPO poll
(BabbageEraOnwards era) {- TODO smelc, use BabbageEraOnly here instead -}
Text -- ^ Prompt
[Text] -- ^ Choices
(Maybe Word) -- ^ Nonce
(File GovernancePoll Out)
| GovernanceAnswerPoll -- ^ Answer a SPO poll
(BabbageEraOnwards era) {- TODO smelc, use BabbageEraOnly here instead -}
(File GovernancePoll In) -- ^ Poll file
(Maybe Word) -- ^ Answer index
(Maybe (File () Out)) -- ^ Tx file
| GovernanceVerifyPoll -- ^ Verify answer to a given SPO poll
(BabbageEraOnwards era) {- TODO smelc, use BabbageEraOnly here instead -}
(File GovernancePoll In) -- Poll file
(File (Tx ()) In) -- Tx file
(Maybe (File () Out)) -- Tx file


renderGovernancePollCmds :: ()
=> GovernancePollCmds era
-> Text
renderGovernancePollCmds = \case
GovernanceCreatePoll {} -> "governance create-poll"
GovernanceAnswerPoll {} -> "governance answer-poll"
GovernanceVerifyPoll {} -> "governance verify-poll"
2 changes: 2 additions & 0 deletions cardano-cli/src/Cardano/CLI/EraBased/Options/Governance.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Cardano.CLI.EraBased.Options.Common
import Cardano.CLI.EraBased.Options.Governance.Actions
import Cardano.CLI.EraBased.Options.Governance.Committee
import Cardano.CLI.EraBased.Options.Governance.DRep
import Cardano.CLI.EraBased.Options.Governance.Poll
import Cardano.CLI.EraBased.Options.Governance.Query
import Cardano.CLI.EraBased.Options.Governance.Vote
import Cardano.CLI.Types.Common
Expand All @@ -39,6 +40,7 @@ pGovernanceCmds era envCli =
, fmap GovernanceActionCmds <$> pGovernanceActionCmds era
, fmap GovernanceCommitteeCmds <$> pGovernanceCommitteeCmds era
, fmap GovernanceDRepCmds <$> pGovernanceDRepCmds era
, fmap GovernancePollCmds <$> pGovernancePollCmds era
, fmap GovernanceVoteCmds <$> pGovernanceVoteCmds era
]

Expand Down
64 changes: 64 additions & 0 deletions cardano-cli/src/Cardano/CLI/EraBased/Options/Governance/Poll.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
module Cardano.CLI.EraBased.Options.Governance.Poll
( pGovernancePollCmds,
)
where

import Cardano.Api

import Cardano.CLI.EraBased.Commands.Governance.Poll (GovernancePollCmds (..))
import Cardano.CLI.EraBased.Options.Common

import Data.Foldable
import Options.Applicative hiding (help, str)
import qualified Options.Applicative as Opt

pGovernancePollCmds ::
() =>
CardanoEra era ->
Maybe (Parser (GovernancePollCmds era))
pGovernancePollCmds era =
asum
[ subParser "create-poll"
<$> ( Opt.info
<$> pGovernanceCreatePoll era
<*> pure (Opt.progDesc "Create an SPO poll")
),
subParser "answer-poll"
<$> ( Opt.info
<$> pGovernanceAnswerPoll era
<*> pure (Opt.progDesc "Answer an SPO poll")
),
subParser "verify-poll"
<$> ( Opt.info
<$> pGovernanceVerifyPoll era
<*> pure (Opt.progDesc "Verify an answer to a given SPO poll")
)
]

pGovernanceCreatePoll :: CardanoEra era -> Maybe (Parser (GovernancePollCmds era))
pGovernanceCreatePoll era = do
w <- maybeEonInEra era
pure $
GovernanceCreatePoll w
<$> pPollQuestion
<*> some pPollAnswer
<*> optional pPollNonce
<*> pOutputFile

pGovernanceAnswerPoll :: CardanoEra era -> Maybe (Parser (GovernancePollCmds era))
pGovernanceAnswerPoll era = do
w <- maybeEonInEra era
pure $
GovernanceAnswerPoll w
<$> pPollFile
<*> optional pPollAnswerIndex
<*> optional pOutputFile

pGovernanceVerifyPoll :: CardanoEra era -> Maybe (Parser (GovernancePollCmds era))
pGovernanceVerifyPoll era = do
w <- maybeEonInEra era
pure $
GovernanceVerifyPoll w
<$> pPollFile
<*> pPollTxFile
<*> optional pOutputFile
5 changes: 5 additions & 0 deletions cardano-cli/src/Cardano/CLI/EraBased/Run.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import Cardano.CLI.Types.Errors.CmdError
import Control.Monad.Trans.Except
import Control.Monad.Trans.Except.Extra (firstExceptT)
import Data.Function ((&))
import Cardano.CLI.EraBased.Run.Governance.Poll (runGovernancePollCmds)

runAnyEraCommand :: ()
=> AnyEraCommand
Expand Down Expand Up @@ -95,6 +96,10 @@ runGovernanceCmds = \case
GovernanceDRepCmds cmds ->
runGovernanceDRepCmds cmds

GovernancePollCmds cmds ->
runGovernancePollCmds cmds
& firstExceptT CmdGovernanceCmdError

GovernanceVoteCmds cmds ->
runGovernanceVoteCmds cmds

Expand Down
170 changes: 170 additions & 0 deletions cardano-cli/src/Cardano/CLI/EraBased/Run/Governance/Poll.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Cardano.CLI.EraBased.Run.Governance.Poll
( runGovernancePollCmds
) where

import Cardano.Api
import Cardano.Api.Shelley
import qualified Cardano.Api.Shelley as Api

import Cardano.CLI.EraBased.Commands.Governance.Poll
import Cardano.CLI.Read
import Cardano.CLI.Types.Errors.GovernanceCmdError

import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.Except (ExceptT)
import Control.Monad.Trans.Except.Extra
import qualified Data.ByteString.Char8 as BSC
import Data.Function ((&))
import Data.String (fromString)
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
import qualified Data.Text.IO as Text
import qualified Data.Text.Read as Text
import qualified System.IO as IO
import System.IO (stderr, stdin, stdout)


runGovernancePollCmds :: GovernancePollCmds era -> ExceptT GovernanceCmdError IO ()
runGovernancePollCmds = \case
GovernanceCreatePoll w prompt choices nonce out ->
runGovernanceCreatePoll w prompt choices nonce out
GovernanceAnswerPoll w poll ix mOutFile ->
runGovernanceAnswerPoll w poll ix mOutFile
GovernanceVerifyPoll w poll metadata mOutFile ->
runGovernanceVerifyPoll w poll metadata mOutFile

runGovernanceCreatePoll
:: BabbageEraOnwards era
-> Text
-> [Text]
-> Maybe Word
-> File GovernancePoll Out
-> ExceptT GovernanceCmdError IO ()
runGovernanceCreatePoll _w govPollQuestion govPollAnswers govPollNonce out = do
let poll = GovernancePoll{ govPollQuestion, govPollAnswers, govPollNonce }

let description = fromString $ "An on-chain poll for SPOs: " <> Text.unpack govPollQuestion
firstExceptT GovernanceCmdTextEnvWriteError . newExceptT $
writeFileTextEnvelope out (Just description) poll

let metadata = asTxMetadata poll
& metadataToJson TxMetadataJsonDetailedSchema

let outPath = unFile out & Text.encodeUtf8 . Text.pack

liftIO $ do
BSC.hPutStrLn stderr $ mconcat
[ "Poll created successfully.\n"
, "Please submit a transaction using the resulting metadata.\n"
]
BSC.hPutStrLn stdout (prettyPrintJSON metadata)
BSC.hPutStrLn stderr $ mconcat
[ "\n"
, "Hint (1): Use '--json-metadata-detailed-schema' and '--metadata-json-file' "
, "from the build or build-raw commands.\n"
, "Hint (2): You can redirect the standard output of this command to a JSON "
, "file to capture metadata.\n\n"
, "Note: A serialized version of the poll suitable for sharing with "
, "participants has been generated at '" <> outPath <> "'."
]

runGovernanceAnswerPoll
:: BabbageEraOnwards era
-> File GovernancePoll In
-> Maybe Word -- ^ Answer index
-> Maybe (File () Out) -- ^ Output file
-> ExceptT GovernanceCmdError IO ()
runGovernanceAnswerPoll _ pollFile maybeChoice mOutFile = do
poll <- firstExceptT GovernanceCmdTextEnvReadError . newExceptT $
readFileTextEnvelope AsGovernancePoll pollFile

choice <- case maybeChoice of
Nothing -> do
askInteractively poll
Just ix -> do
validateChoice poll ix
liftIO $ BSC.hPutStrLn stderr $ Text.encodeUtf8 $ Text.intercalate "\n"
[ govPollQuestion poll
, "" <> (govPollAnswers poll !! fromIntegral ix)
, ""
]
pure ix

let pollAnswer = GovernancePollAnswer
{ govAnsPoll = hashGovernancePoll poll
, govAnsChoice = choice
}
let metadata =
metadataToJson TxMetadataJsonDetailedSchema (asTxMetadata pollAnswer)

liftIO $ BSC.hPutStrLn stderr $ mconcat
[ "Poll answer created successfully.\n"
, "Please submit a transaction using the resulting metadata.\n"
, "To be valid, the transaction must also be signed using a valid key\n"
, "identifying your stake pool (e.g. your cold key).\n"
]

lift (writeByteStringOutput mOutFile (prettyPrintJSON metadata))
& onLeft (left . GovernanceCmdWriteFileError)

liftIO $ BSC.hPutStrLn stderr $ mconcat
[ "\n"
, "Hint (1): Use '--json-metadata-detailed-schema' and '--metadata-json-file' "
, "from the build or build-raw commands.\n"
, "Hint (2): You can redirect the standard output of this command to a JSON "
, "file to capture metadata."
]
where
validateChoice :: GovernancePoll -> Word -> ExceptT GovernanceCmdError IO ()
validateChoice GovernancePoll{govPollAnswers} ix = do
let maxAnswerIndex = length govPollAnswers - 1
when (fromIntegral ix > maxAnswerIndex) $ left $
GovernanceCmdPollOutOfBoundAnswer maxAnswerIndex

askInteractively :: GovernancePoll -> ExceptT GovernanceCmdError IO Word
askInteractively poll@GovernancePoll{govPollQuestion, govPollAnswers} = do
liftIO $ BSC.hPutStrLn stderr $ Text.encodeUtf8 $ Text.intercalate "\n"
( govPollQuestion
: [ "[" <> textShow ix <> "] " <> answer
| (ix :: Int, answer) <- zip [0..] govPollAnswers
]
)
liftIO $ BSC.hPutStrLn stderr ""
liftIO $ BSC.hPutStr stderr "Please indicate an answer (by index): "
txt <- liftIO $ Text.hGetLine stdin
liftIO $ BSC.hPutStrLn stderr ""
case Text.decimal txt of
Right (choice, rest) | Text.null rest ->
choice <$ validateChoice poll choice
_ ->
left GovernanceCmdPollInvalidChoice

runGovernanceVerifyPoll
:: BabbageEraOnwards era
-> File GovernancePoll In
-> File (Api.Tx ()) In
-> Maybe (File () Out) -- ^ Output file
-> ExceptT GovernanceCmdError IO ()
runGovernanceVerifyPoll _ pollFile txFile mOutFile = do
poll <- firstExceptT GovernanceCmdTextEnvReadError . newExceptT $
readFileTextEnvelope AsGovernancePoll pollFile

txFileOrPipe <- liftIO $ fileOrPipe (unFile txFile)
tx <- firstExceptT GovernanceCmdCddlError . newExceptT $
readFileTx txFileOrPipe

signatories <- firstExceptT GovernanceCmdVerifyPollError . newExceptT $ pure $
verifyPollAnswer poll tx

liftIO $ IO.hPutStrLn stderr $ "Found valid poll answer with " <> show (length signatories) <> " signatories"

lift (writeByteStringOutput mOutFile (prettyPrintJSON signatories))
& onLeft (left . GovernanceCmdWriteFileError)
16 changes: 0 additions & 16 deletions cardano-cli/src/Cardano/CLI/Legacy/Commands/Governance.hs
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,6 @@ data LegacyGovernanceCmds
[VerificationKeyFile In]
ProtocolParametersUpdate
(Maybe FilePath)
| GovernanceCreatePoll
Text -- Prompt
[Text] -- Choices
(Maybe Word) -- Nonce
(File GovernancePoll Out)
| GovernanceAnswerPoll
(File GovernancePoll In) -- Poll file
(Maybe Word) -- Answer index
(Maybe (File () Out)) -- Tx file
| GovernanceVerifyPoll
(File GovernancePoll In) -- Poll file
(File (Tx ()) In) -- Tx file
(Maybe (File () Out)) -- Tx file
deriving Show

renderLegacyGovernanceCmds :: LegacyGovernanceCmds -> Text
Expand All @@ -57,7 +44,4 @@ renderLegacyGovernanceCmds = \case
GovernanceMIRTransfer _ _ _ TransferToTreasury -> "governance create-mir-certificate transfer-to-treasury"
GovernanceMIRTransfer _ _ _ TransferToReserves -> "governance create-mir-certificate transfer-to-reserves"
GovernanceUpdateProposal {} -> "governance create-update-proposal"
GovernanceCreatePoll{} -> "governance create-poll"
GovernanceAnswerPoll{} -> "governance answer-poll"
GovernanceVerifyPoll{} -> "governance verify-poll"

Loading

0 comments on commit a20579b

Please sign in to comment.