Skip to content

Commit

Permalink
New drep command.
Browse files Browse the repository at this point in the history
  • Loading branch information
newhoggy committed May 25, 2023
1 parent a7ae2ca commit 66b0127
Show file tree
Hide file tree
Showing 11 changed files with 367 additions and 2 deletions.
1 change: 1 addition & 0 deletions cardano-cli/cardano-cli.cabal
Expand Up @@ -82,6 +82,7 @@ library
Cardano.CLI.Shelley.Run
Cardano.CLI.Shelley.Run.Address
Cardano.CLI.Shelley.Run.Address.Info
Cardano.CLI.Shelley.Run.DRep
Cardano.CLI.Shelley.Run.Genesis
Cardano.CLI.Shelley.Run.Governance
Cardano.CLI.Shelley.Run.Governance.Cc
Expand Down
33 changes: 32 additions & 1 deletion cardano-cli/src/Cardano/CLI/Shelley/Commands.hs
Expand Up @@ -9,6 +9,7 @@ module Cardano.CLI.Shelley.Commands
ShelleyCommand (..)
, AddressCmd (..)
, CcCmd (..)
, DRepCmd (..)
, StakeAddressCmd (..)
, KeyCmd (..)
, TransactionCmd (..)
Expand Down Expand Up @@ -55,7 +56,7 @@ module Cardano.CLI.Shelley.Commands
, GovernanceActionInfoResource(..)
) where

import Cardano.Api.Shelley
import Cardano.Api.Shelley hiding (DRepMetadataHash)

import Cardano.Chain.Common (BlockCount)
import Cardano.CLI.Shelley.Key (PaymentVerifier, PoolDelegationTarget, StakeIdentifier,
Expand All @@ -75,6 +76,7 @@ import Data.Text (Text)
--
data ShelleyCommand
= AddressCmd AddressCmd
| DRepCmd DRepCmd
| StakeAddressCmd StakeAddressCmd
| KeyCmd KeyCmd
| TransactionCmd TransactionCmd
Expand All @@ -89,6 +91,7 @@ renderShelleyCommand :: ShelleyCommand -> Text
renderShelleyCommand sc =
case sc of
AddressCmd cmd -> renderAddressCmd cmd
DRepCmd cmd -> renderDRepCmd cmd
StakeAddressCmd cmd -> renderStakeAddressCmd cmd
KeyCmd cmd -> renderKeyCmd cmd
TransactionCmd cmd -> renderTransactionCmd cmd
Expand Down Expand Up @@ -369,6 +372,26 @@ data PoolCmd
| PoolMetadataHash (File StakePoolMetadata In) (Maybe (File () Out))
deriving Show

data DRepCmd
= DRepRegistrationCert
NetworkId
-- ^ Network ID.
(VerificationKeyOrFile DRepKey)
-- ^ VRF Verification key.
(Maybe DRepMetadataReference)
-- ^ DRep metadata.
(File Certificate Out)
-- ^ File path to where the certificate will be written.
| DRepRetirementCert
(VerificationKeyOrFile DRepKey)
-- ^ DRep verification key.
EpochNo
-- ^ Epoch in which to retire the DRep.
(File Certificate Out)
| DRepGetId (VerificationKeyOrFile DRepKey) OutputFormat
| DRepMetadataHash (File DRepMetadata In) (Maybe (File () Out))
deriving Show

renderPoolCmd :: PoolCmd -> Text
renderPoolCmd cmd =
case cmd of
Expand All @@ -377,6 +400,14 @@ renderPoolCmd cmd =
PoolGetId {} -> "stake-pool id"
PoolMetadataHash {} -> "stake-pool metadata-hash"

renderDRepCmd :: DRepCmd -> Text
renderDRepCmd cmd =
case cmd of
DRepRegistrationCert {} -> "drep registration-certificate"
DRepRetirementCert {} -> "drep deregistration-certificate"
DRepGetId {} -> "drep id"
DRepMetadataHash {} -> "drep metadata-hash"

data QueryCmd =
QueryLeadershipSchedule
SocketPath
Expand Down
107 changes: 106 additions & 1 deletion cardano-cli/src/Cardano/CLI/Shelley/Parsers.hs
Expand Up @@ -16,7 +16,7 @@ module Cardano.CLI.Shelley.Parsers
) where

import Cardano.Api
import Cardano.Api.Shelley
import Cardano.Api.Shelley hiding (DRepMetadataHash)

import Cardano.Chain.Common (BlockCount (BlockCount))
import Cardano.CLI.Common.Parsers
Expand Down Expand Up @@ -88,6 +88,8 @@ parseShelleyCommands envCli =
Opt.info (NodeCmd <$> pNodeCmd) $ Opt.progDesc "Node operation commands"
, Opt.command "stake-pool" $
Opt.info (PoolCmd <$> pPoolCmd envCli) $ Opt.progDesc "Stake pool commands"
, Opt.command "drep" $
Opt.info (DRepCmd <$> pDRepCmd envCli) $ Opt.progDesc "DRep commands"
, Opt.command "query" $
Opt.info (QueryCmd <$> pQueryCmd envCli) . Opt.progDesc $ mconcat
[ "Node query commands. Will query the local node whose Unix domain socket "
Expand Down Expand Up @@ -1003,6 +1005,25 @@ pPoolCmd envCli =
pPoolMetadataHashSubCmd :: Parser PoolCmd
pPoolMetadataHashSubCmd = PoolMetadataHash <$> pPoolMetadataFile <*> pMaybeOutputFile

pDRepCmd :: EnvCli -> Parser DRepCmd
pDRepCmd envCli =
asum
[ subParser "registration-certificate"
(Opt.info (pDRepRegistrationCert envCli) $ Opt.progDesc "Create a DRep registration certificate")
, subParser "deregistration-certificate"
(Opt.info pDRepRetirementCert $ Opt.progDesc "Create a DRep deregistration certificate")
, subParser "id"
(Opt.info pId $ Opt.progDesc "Build DRep id from the offline key")
, subParser "metadata-hash"
(Opt.info pDRepMetadataHashSubCmd $ Opt.progDesc "Print the hash of DRep metadata.")
]
where
pId :: Parser DRepCmd
pId = DRepGetId <$> pDRepVerificationKeyOrFile <*> pOutputFormat

pDRepMetadataHashSubCmd :: Parser DRepCmd
pDRepMetadataHashSubCmd = DRepMetadataHash <$> pDRepMetadataFile <*> pMaybeOutputFile

pQueryCmd :: EnvCli -> Parser QueryCmd
pQueryCmd envCli =
asum
Expand Down Expand Up @@ -1936,6 +1957,15 @@ pPoolMetadataFile =
, Opt.completer (Opt.bashCompleter "file")
]

pDRepMetadataFile :: Parser (File DRepMetadata In)
pDRepMetadataFile =
fmap File $ Opt.strOption $ mconcat
[ Opt.long "drep-metadata-file"
, Opt.metavar "FILE"
, Opt.help "Filepath of the drep metadata."
, Opt.completer (Opt.bashCompleter "file")
]

pTxMetadataJsonSchema :: Parser TxMetadataJsonSchema
pTxMetadataJsonSchema =
( Opt.flag' ()
Expand Down Expand Up @@ -3152,6 +3182,36 @@ pPoolVerificationKeyOrFile =
, VerificationKeyFilePath <$> pStakePoolVerificationKeyFile
]

pDRepVerificationKeyFile :: Parser (VerificationKeyFile In)
pDRepVerificationKeyFile =
fmap File $ asum
[ Opt.strOption $ mconcat
[ Opt.long "cold-verification-key-file"
, Opt.metavar "FILE"
, Opt.help "Filepath of the drep verification key."
, Opt.completer (Opt.bashCompleter "file")
]
, Opt.strOption $ mconcat
[ Opt.long "drep-verification-key-file"
, Opt.internal
]
]

pDRepVerificationKey :: Parser (VerificationKey DRepKey)
pDRepVerificationKey =
Opt.option
(readVerificationKey AsDRepKey)
( Opt.long "drep-verification-key"
<> Opt.metavar "STRING"
<> Opt.help "DRep verification key (Bech32 or hex-encoded)."
)

pDRepVerificationKeyOrFile
:: Parser (VerificationKeyOrFile DRepKey)
pDRepVerificationKeyOrFile =
VerificationKeyValue <$> pDRepVerificationKey
<|> VerificationKeyFilePath <$> pDRepVerificationKeyFile

pPoolDelegationTarget
:: Parser PoolDelegationTarget
pPoolDelegationTarget = PoolDelegationTarget <$> pPoolVerificationKeyOrHashOrFile
Expand Down Expand Up @@ -3419,6 +3479,51 @@ pStakePoolRetirementCert =
<*> pEpochNo
<*> pOutputFile

pDRepMetadataReference :: Parser (Maybe DRepMetadataReference)
pDRepMetadataReference =
optional $
DRepMetadataReference
<$> pDRepMetadataUrl
<*> pDRepMetadataHash

pDRepMetadataUrl :: Parser Text
pDRepMetadataUrl =
Opt.option (readURIOfMaxLength 64)
( Opt.long "metadata-url"
<> Opt.metavar "URL"
<> Opt.help "Pool metadata URL (maximum length of 64 characters)."
)

pDRepMetadataHash :: Parser (Hash DRepMetadata)
pDRepMetadataHash =
Opt.option
(Opt.eitherReader metadataHash)
( Opt.long "metadata-hash"
<> Opt.metavar "HASH"
<> Opt.help "Pool metadata hash."
)
where
metadataHash :: String -> Either String (Hash DRepMetadata)
metadataHash =
first displayError
. deserialiseFromRawBytesHex (AsHash AsDRepMetadata)
. BSC.pack

pDRepRegistrationCert :: EnvCli -> Parser DRepCmd
pDRepRegistrationCert envCli =
DRepRegistrationCert
<$> pNetworkId envCli
<*> pDRepVerificationKeyOrFile
<*> pDRepMetadataReference
<*> pOutputFile

pDRepRetirementCert :: Parser DRepCmd
pDRepRetirementCert =
DRepRetirementCert
<$> pDRepVerificationKeyOrFile
<*> pEpochNo
<*> pOutputFile

pProtocolParametersUpdate :: Parser ProtocolParametersUpdate
pProtocolParametersUpdate =
ProtocolParametersUpdate
Expand Down
5 changes: 5 additions & 0 deletions cardano-cli/src/Cardano/CLI/Shelley/Run.hs
Expand Up @@ -8,6 +8,7 @@ import Cardano.Api

import Cardano.CLI.Shelley.Parsers
import Cardano.CLI.Shelley.Run.Address
import Cardano.CLI.Shelley.Run.DRep
import Cardano.CLI.Shelley.Run.Genesis
import Cardano.CLI.Shelley.Run.Governance
import Cardano.CLI.Shelley.Run.Key
Expand All @@ -25,6 +26,7 @@ import qualified Data.Text as Text

data ShelleyClientCmdError
= ShelleyCmdAddressError !ShelleyAddressCmdError
| ShelleyCmdDRepError !ShelleyDRepCmdError
| ShelleyCmdGenesisError !ShelleyGenesisCmdError
| ShelleyCmdGovernanceError !ShelleyGovernanceCmdError
| ShelleyCmdNodeError !ShelleyNodeCmdError
Expand All @@ -40,6 +42,8 @@ renderShelleyClientCmdError cmd err =
case err of
ShelleyCmdAddressError addrCmdErr ->
renderError cmd renderShelleyAddressCmdError addrCmdErr
ShelleyCmdDRepError addrCmdErr ->
renderError cmd renderShelleyDRepCmdError addrCmdErr
ShelleyCmdGenesisError genesisCmdErr ->
renderError cmd (Text.pack . displayError) genesisCmdErr
ShelleyCmdGovernanceError govCmdErr ->
Expand Down Expand Up @@ -74,6 +78,7 @@ renderShelleyClientCmdError cmd err =

runShelleyClientCommand :: ShelleyCommand -> ExceptT ShelleyClientCmdError IO ()
runShelleyClientCommand (AddressCmd cmd) = firstExceptT ShelleyCmdAddressError $ runAddressCmd cmd
runShelleyClientCommand (DRepCmd cmd) = firstExceptT ShelleyCmdDRepError $ runDRepCmd cmd
runShelleyClientCommand (StakeAddressCmd cmd) = firstExceptT ShelleyCmdStakeAddressError $ runStakeAddressCmd cmd
runShelleyClientCommand (KeyCmd cmd) = firstExceptT ShelleyCmdKeyError $ runKeyCmd cmd
runShelleyClientCommand (TransactionCmd cmd) = firstExceptT ShelleyCmdTransactionError $ runTransactionCmd cmd
Expand Down
110 changes: 110 additions & 0 deletions cardano-cli/src/Cardano/CLI/Shelley/Run/DRep.hs
@@ -0,0 +1,110 @@
{-# LANGUAGE DataKinds #-}

module Cardano.CLI.Shelley.Run.DRep
( ShelleyDRepCmdError(ShelleyDRepCmdReadFileError)
, renderShelleyDRepCmdError
, runDRepCmd
) where

import Cardano.Api

import Cardano.CLI.Shelley.Commands
import Cardano.CLI.Shelley.Key (VerificationKeyOrFile, readVerificationKeyOrFile)
import Cardano.CLI.Types (OutputFormat (..))
import qualified Cardano.Ledger.Slot as Shelley

import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.Trans (lift)
import Control.Monad.Trans.Except (ExceptT)
import Control.Monad.Trans.Except.Extra (firstExceptT, handleIOExceptT, hoistEither, left,
newExceptT, onLeft)
import qualified Data.ByteString.Char8 as BS
import Data.Function ((&))
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.IO as Text

data ShelleyDRepCmdError
= ShelleyDRepCmdReadFileError !(FileError TextEnvelopeError)
| ShelleyDRepCmdReadKeyFileError !(FileError InputDecodeError)
| ShelleyDRepCmdWriteFileError !(FileError ())
| ShelleyDRepCmdMetadataValidationError !DRepMetadataValidationError
deriving Show

renderShelleyDRepCmdError :: ShelleyDRepCmdError -> Text
renderShelleyDRepCmdError err =
case err of
ShelleyDRepCmdReadFileError fileErr -> Text.pack (displayError fileErr)
ShelleyDRepCmdReadKeyFileError fileErr -> Text.pack (displayError fileErr)
ShelleyDRepCmdWriteFileError fileErr -> Text.pack (displayError fileErr)
ShelleyDRepCmdMetadataValidationError validationErr ->
"Error validating drep metadata: " <> Text.pack (displayError validationErr)



runDRepCmd :: DRepCmd -> ExceptT ShelleyDRepCmdError IO ()
runDRepCmd (DRepRegistrationCert network sPvkey mbMetadata outfp) =
runDRepRegistrationCert network sPvkey mbMetadata outfp
runDRepCmd (DRepRetirementCert sPvkeyFp retireEpoch outfp) =
runDRepRetirementCert sPvkeyFp retireEpoch outfp
runDRepCmd (DRepGetId sPvkey outputFormat) = runDRepId sPvkey outputFormat
runDRepCmd (DRepMetadataHash drepMetadataFile mOutFile) = runDRepMetadataHash drepMetadataFile mOutFile

--
-- DRep command implementations
--

-- | Create a drep registration cert.
-- TODO: Metadata and more drep relay support to be
-- added in the future.
runDRepRegistrationCert
:: NetworkId
-- ^ Network ID.
-> VerificationKeyOrFile DRepKey
-- ^ DRep verification key.
-> Maybe DRepMetadataReference
-- ^ DRep metadata.
-> File Certificate Out
-> ExceptT ShelleyDRepCmdError IO ()
runDRepRegistrationCert
_network
_drepVerKeyOrFile
_mbMetadata
_outfp = error "Not implemented"

runDRepRetirementCert
:: VerificationKeyOrFile DRepKey
-> Shelley.EpochNo
-> File Certificate Out
-> ExceptT ShelleyDRepCmdError IO ()
runDRepRetirementCert _drepVerKeyOrFile _retireEpoch _outfp = error "Not implemented"

runDRepId
:: VerificationKeyOrFile DRepKey
-> OutputFormat
-> ExceptT ShelleyDRepCmdError IO ()
runDRepId verKeyOrFile outputFormat = do
drepVerKey <- firstExceptT ShelleyDRepCmdReadKeyFileError
. newExceptT
$ readVerificationKeyOrFile AsDRepKey verKeyOrFile
liftIO $
case outputFormat of
OutputFormatHex ->
BS.putStrLn $ serialiseToRawBytesHex (verificationKeyHash drepVerKey)
OutputFormatBech32 ->
Text.putStrLn $ serialiseToBech32 (verificationKeyHash drepVerKey)

runDRepMetadataHash :: File DRepMetadata In -> Maybe (File () Out) -> ExceptT ShelleyDRepCmdError IO ()
runDRepMetadataHash drepMDPath mOutFile = do
metadataBytes <- lift (readByteStringFile drepMDPath)
& onLeft (left . ShelleyDRepCmdReadFileError)

(_metadata, metadataHash) <-
firstExceptT ShelleyDRepCmdMetadataValidationError
. hoistEither
$ validateAndHashDRepMetadata metadataBytes
case mOutFile of
Nothing -> liftIO $ BS.putStrLn (serialiseToRawBytesHex metadataHash)
Just (File fpath) ->
handleIOExceptT (ShelleyDRepCmdWriteFileError . FileIOError fpath)
$ BS.writeFile fpath (serialiseToRawBytesHex metadataHash)

0 comments on commit 66b0127

Please sign in to comment.