Skip to content

Commit

Permalink
Implement hash checks for registration-certificate and `update-cert…
Browse files Browse the repository at this point in the history
…ificate`
  • Loading branch information
palas committed Oct 3, 2024
1 parent 2b400b5 commit 96b3648
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 17 deletions.
16 changes: 14 additions & 2 deletions cardano-cli/src/Cardano/CLI/EraBased/Commands/Governance/DRep.hs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@ data GovernanceDRepRegistrationCertificateCmdArgs era
{ eon :: !(ConwayEraOnwards era)
, drepHashSource :: !DRepHashSource
, deposit :: !Lovelace
, mAnchor :: !(Maybe (L.Anchor (L.EraCrypto (ShelleyLedgerEra era))))
, mPotentiallyCheckedAnchor
:: !( Maybe
( PotentiallyCheckedAnchor
DRepMetadataUrl
(L.Anchor (L.EraCrypto (ShelleyLedgerEra era)))
)
)
, outFile :: !(File () Out)
}

Expand All @@ -67,7 +73,13 @@ data GovernanceDRepUpdateCertificateCmdArgs era
= GovernanceDRepUpdateCertificateCmdArgs
{ eon :: !(ConwayEraOnwards era)
, drepHashSource :: !DRepHashSource
, mAnchor :: !(Maybe (L.Anchor (L.EraCrypto (ShelleyLedgerEra era))))
, mPotentiallyCheckedAnchor
:: !( Maybe
( PotentiallyCheckedAnchor
DRepMetadataUrl
(L.Anchor (L.EraCrypto (ShelleyLedgerEra era)))
)
)
, outFile :: !(File () Out)
}

Expand Down
12 changes: 12 additions & 0 deletions cardano-cli/src/Cardano/CLI/EraBased/Options/Common.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3595,12 +3595,24 @@ pMustCheckHash flagSuffix' dataName' hashParamName' urlParamName' =
]
]

pPotentiallyCheckedAnchorData
:: Parser (MustCheckHash anchorDataType)
-> Parser anchorData
-> Parser (PotentiallyCheckedAnchor anchorDataType anchorData)
pPotentiallyCheckedAnchorData mustCheckHash anchorData =
PotentiallyCheckedAnchor
<$> anchorData
<*> mustCheckHash

pMustCheckProposalHash :: Parser (MustCheckHash ProposalUrl)
pMustCheckProposalHash = pMustCheckHash "anchor-data" "proposal" "--anchor-data-hash" "--anchor-url"

pMustCheckConstitutionHash :: Parser (MustCheckHash ConstitutionUrl)
pMustCheckConstitutionHash = pMustCheckHash "constitution-hash" "constitution" "--constitution-hash" "--constitution-url"

pMustCheckMetadataHash :: Parser (MustCheckHash DRepMetadataUrl)
pMustCheckMetadataHash = pMustCheckHash "drep-metadata-hash" "DRep metadata" "--drep-metadata-hash" "--drep-metadata-url"

pPreviousGovernanceAction :: Parser (Maybe (TxId, Word16))
pPreviousGovernanceAction =
optional $
Expand Down
21 changes: 14 additions & 7 deletions cardano-cli/src/Cardano/CLI/EraBased/Options/Governance/DRep.hs
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,18 @@ pRegistrationCertificateCmd era = do
GovernanceDRepRegistrationCertificateCmdArgs w
<$> pDRepHashSource
<*> pKeyRegistDeposit
<*> pDRepMetadata
<*> optional
( pPotentiallyCheckedAnchorData
pMustCheckMetadataHash
pDRepMetadata
)
<*> pOutputFile

pDRepMetadata :: Parser (Maybe (L.Anchor L.StandardCrypto))
pDRepMetadata :: Parser (L.Anchor L.StandardCrypto)
pDRepMetadata =
optional $
L.Anchor
<$> fmap unAnchorUrl pDrepMetadataUrl
<*> pDrepMetadataHash
L.Anchor
<$> fmap unAnchorUrl pDrepMetadataUrl
<*> pDrepMetadataHash

pDrepMetadataUrl :: Parser AnchorUrl
pDrepMetadataUrl =
Expand Down Expand Up @@ -165,7 +168,11 @@ pUpdateCertificateCmd era = do
conwayEraOnwardsConstraints w $
GovernanceDRepUpdateCertificateCmdArgs w
<$> pDRepHashSource
<*> pDRepMetadata
<*> optional
( pPotentiallyCheckedAnchorData
pMustCheckMetadataHash
pDRepMetadata
)
<*> pOutputFile
)
$ Opt.progDesc "Create a DRep update certificate."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -530,5 +530,5 @@ carryHashChecks checkHash anchor checkType =
let hash = L.hashAnchorData anchorData
when (hash /= L.anchorDataHash anchor) $
left $
GovernanceActionsProposalMismatchedHashError checkType (L.anchorDataHash anchor) hash
GovernanceActionsMismatchedHashError checkType (L.anchorDataHash anchor) hash
TrustHash -> pure ()
52 changes: 47 additions & 5 deletions cardano-cli/src/Cardano/CLI/EraBased/Run/Governance/DRep.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,19 @@ module Cardano.CLI.EraBased.Run.Governance.DRep
where

import Cardano.Api
import qualified Cardano.Api.Ledger as L

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.Types.Common
import Cardano.CLI.Types.Errors.CmdError
import Cardano.CLI.Types.Errors.GovernanceCmdError
import Cardano.CLI.Types.Errors.HashCmdError (FetchURLError)
import Cardano.CLI.Types.Errors.RegistrationError
import Cardano.CLI.Types.Key

import Control.Monad (void)
import Control.Monad (void, when)
import Data.Function
import qualified Data.Text.Encoding as Text

Expand Down Expand Up @@ -103,13 +106,21 @@ runGovernanceDRepRegistrationCertificateCmd
{ eon = w
, drepHashSource
, deposit
, mAnchor
, mPotentiallyCheckedAnchor
, outFile
} =
conwayEraOnwardsConstraints w $ do
drepCred <- modifyError RegistrationReadError $ readDRepCredential drepHashSource

mapM_
(carryHashChecks RegistrationFetchURLError RegistrationMismatchedDRepMetadataHashError)
mPotentiallyCheckedAnchor

let req = DRepRegistrationRequirements w drepCred deposit
registrationCert = makeDrepRegistrationCertificate req mAnchor
registrationCert =
makeDrepRegistrationCertificate
req
(pcaAnchor <$> mPotentiallyCheckedAnchor)
description = Just @TextEnvelopeDescr "DRep Key Registration Certificate"

firstExceptT RegistrationWriteFileError
Expand Down Expand Up @@ -146,12 +157,18 @@ runGovernanceDRepUpdateCertificateCmd
Cmd.GovernanceDRepUpdateCertificateCmdArgs
{ eon = w
, drepHashSource
, mAnchor
, mPotentiallyCheckedAnchor
, outFile
} =
conwayEraOnwardsConstraints w $ do
mapM_
(carryHashChecks GovernanceCmdFetchURLError GovernanceCmdMismatchedDRepMetadataHashError)
mPotentiallyCheckedAnchor
drepCredential <- modifyError GovernanceCmdKeyReadError $ readDRepCredential drepHashSource
let updateCertificate = makeDrepUpdateCertificate (DRepUpdateRequirements w drepCredential) mAnchor
let updateCertificate =
makeDrepUpdateCertificate
(DRepUpdateRequirements w drepCredential)
(pcaAnchor <$> mPotentiallyCheckedAnchor)
firstExceptT GovernanceCmdTextEnvWriteError . newExceptT $
writeFileTextEnvelope outFile (Just "DRep Update Certificate") updateCertificate

Expand All @@ -171,3 +188,28 @@ runGovernanceDRepMetadataHashCmd
. writeByteStringOutput mOutFile
. serialiseToRawBytesHex
$ metadataHash

-- | Check the hash of the anchor data against the hash in the anchor if
-- checkHash is set to CheckHash.
carryHashChecks
:: (FetchURLError -> error)
-- ^ Function that takes a FetchURLError and returns the error type of the caller
-> (L.SafeHash L.StandardCrypto L.AnchorData -> L.SafeHash L.StandardCrypto L.AnchorData -> error)
-- ^ Function that takes the expected and actual hashes and returns the mismatch hash error type of the caller
-> PotentiallyCheckedAnchor DRepMetadataUrl (L.Anchor L.StandardCrypto)
-- ^ The information about anchor data and whether to check the hash (see 'PotentiallyCheckedAnchor')
-> ExceptT error IO ()
carryHashChecks errorAdaptor hashMismatchError potentiallyCheckedAnchor =
let anchor = pcaAnchor potentiallyCheckedAnchor
in case pcaMustCheck potentiallyCheckedAnchor of
CheckHash -> do
anchorData <-
L.AnchorData
<$> withExceptT
errorAdaptor
(getByteStringFromURL httpsAndIpfsSchemas $ L.anchorUrl anchor)
let hash = L.hashAnchorData anchorData
when (hash /= L.anchorDataHash anchor) $
left $
hashMismatchError (L.anchorDataHash anchor) hash
TrustHash -> pure ()
15 changes: 15 additions & 0 deletions cardano-cli/src/Cardano/CLI/Types/Common.hs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ module Cardano.CLI.Types.Common
, WitnessFile (..)
, WitnessSigningData (..)
, DRepMetadataFile
, DRepMetadataUrl
, PotentiallyCheckedAnchor (..)
)
where

Expand Down Expand Up @@ -137,6 +139,10 @@ data ProposalBinary
-- | Tag for tracking proposals submitted as 'Text.Text'
data ProposalText

-- | Tag for differentiating between DRep metadata sources and
-- sources for other types of anchor data
data DRepMetadataUrl

newtype VoteUrl = VoteUrl
{ unVoteUrl :: L.Url
}
Expand Down Expand Up @@ -645,3 +651,12 @@ data MustCheckHash a
= CheckHash
| TrustHash
deriving (Eq, Show)

data PotentiallyCheckedAnchor anchorType anchor
= PotentiallyCheckedAnchor
{ pcaAnchor :: anchor
-- ^ The anchor data whose hash is to be checked
, pcaMustCheck :: MustCheckHash anchorType
-- ^ Whether to check the hash or not (CheckHash for checking or TrustHash for not checking)
}
deriving (Eq, Show)
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ data GovernanceActionsError
| GovernanceActionsCmdReadTextEnvelopeFileError (FileError TextEnvelopeError)
| GovernanceActionsCmdWriteFileError (FileError ())
| GovernanceActionsValueUpdateProtocolParametersNotFound AnyShelleyBasedEra
| GovernanceActionsProposalMismatchedHashError
| GovernanceActionsMismatchedHashError
AnchorDataTypeCheck
-- ^ Type of anchor data that we were checking
!(L.SafeHash L.StandardCrypto L.AnchorData)
Expand Down Expand Up @@ -56,7 +56,7 @@ instance Error GovernanceActionsError where
"Protocol parameters update value for" <+> pretty expectedShelleyEra <+> "was not found."
GovernanceActionsReadStakeCredErrror e ->
prettyError e
GovernanceActionsProposalMismatchedHashError adt expectedHash actualHash ->
GovernanceActionsMismatchedHashError adt expectedHash actualHash ->
"Hashes do not match while checking"
<+> pretty (anchorDataTypeCheckName adt)
<+> "hashes!"
Expand Down
15 changes: 15 additions & 0 deletions cardano-cli/src/Cardano/CLI/Types/Errors/GovernanceCmdError.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
module Cardano.CLI.Types.Errors.GovernanceCmdError where

import Cardano.Api
import qualified Cardano.Api.Ledger as L
import Cardano.Api.Shelley

import Cardano.Binary (DecoderError)
import Cardano.CLI.Read
import Cardano.CLI.Types.Errors.HashCmdError (FetchURLError)
import Cardano.CLI.Types.Errors.StakeAddressCmdError

import Control.Exception (displayException)
import qualified Data.List as List
import Data.Text (Text)
import qualified Data.Text.Lazy.Builder as TL
Expand Down Expand Up @@ -53,6 +56,10 @@ data GovernanceCmdError
| -- Legacy - remove me after cardano-cli transitions to new era based structure
GovernanceCmdMIRCertNotSupportedInConway
| GovernanceCmdGenesisDelegationNotSupportedInConway
| GovernanceCmdMismatchedDRepMetadataHashError
!(L.SafeHash L.StandardCrypto L.AnchorData)
!(L.SafeHash L.StandardCrypto L.AnchorData)
| GovernanceCmdFetchURLError !FetchURLError
deriving Show

instance Error GovernanceCmdError where
Expand Down Expand Up @@ -114,5 +121,13 @@ instance Error GovernanceCmdError where
"MIR certificates are not supported in Conway era onwards."
GovernanceCmdGenesisDelegationNotSupportedInConway ->
"Genesis delegation is not supported in Conway era onwards."
GovernanceCmdMismatchedDRepMetadataHashError expectedHash actualHash ->
"DRep metadata Hashes do not match!"
<> "\nExpected:"
<+> pretty (show (L.extractHash expectedHash))
<> "\n Actual:"
<+> pretty (show (L.extractHash actualHash))
GovernanceCmdFetchURLError fetchErr ->
"Error while fetching proposal: " <> pretty (displayException fetchErr)
where
renderDecoderError = pretty . TL.toLazyText . B.build
16 changes: 16 additions & 0 deletions cardano-cli/src/Cardano/CLI/Types/Errors/RegistrationError.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,23 @@ module Cardano.CLI.Types.Errors.RegistrationError
where

import Cardano.Api
import qualified Cardano.Api.Ledger as L

import Cardano.CLI.Types.Errors.HashCmdError (FetchURLError)
import Cardano.CLI.Types.Errors.StakeAddressRegistrationError
import Cardano.CLI.Types.Errors.StakeCredentialError

import Control.Exception (displayException)

data RegistrationError
= RegistrationReadError !(FileError InputDecodeError)
| RegistrationWriteFileError !(FileError ())
| RegistrationStakeCredentialError !StakeCredentialError
| RegistrationStakeError !StakeAddressRegistrationError
| RegistrationMismatchedDRepMetadataHashError
!(L.SafeHash L.StandardCrypto L.AnchorData)
!(L.SafeHash L.StandardCrypto L.AnchorData)
| RegistrationFetchURLError !FetchURLError
deriving Show

instance Error RegistrationError where
Expand All @@ -27,3 +35,11 @@ instance Error RegistrationError where
"Cannot read stake credential: " <> prettyError e
RegistrationStakeError e ->
"Stake address registation error: " <> prettyError e
RegistrationMismatchedDRepMetadataHashError expectedHash actualHash ->
"DRep metadata Hashes do not match!"
<> "\nExpected:"
<+> pretty (show (L.extractHash expectedHash))
<> "\n Actual:"
<+> pretty (show (L.extractHash actualHash))
RegistrationFetchURLError fetchErr ->
"Error while fetching proposal: " <> pretty (displayException fetchErr)

0 comments on commit 96b3648

Please sign in to comment.