Skip to content

Commit

Permalink
Add certs to compatible transaction build command
Browse files Browse the repository at this point in the history
* Added reference test for `compatible conway transaction singed-transaction`
  • Loading branch information
carbolymer committed Jan 15, 2025
1 parent eecd898 commit 3b889d3
Show file tree
Hide file tree
Showing 12 changed files with 686 additions and 41 deletions.
1 change: 1 addition & 0 deletions cardano-cli/cardano-cli.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ test-suite cardano-cli-test
Test.Cli.Shelley.Run.Hash
Test.Cli.Shelley.Run.Query
Test.Cli.Shelley.Transaction.Build
Test.Cli.Shelley.Transaction.Compatible.Build
Test.Cli.VerificationKey

ghc-options:
Expand Down
132 changes: 109 additions & 23 deletions cardano-cli/src/Cardano/CLI/Compatible/Transaction.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}

module Cardano.CLI.Compatible.Transaction
Expand All @@ -27,10 +28,15 @@ import Cardano.CLI.Types.Common
import Cardano.CLI.Types.Errors.BootstrapWitnessError
import Cardano.CLI.Types.Errors.TxCmdError
import Cardano.CLI.Types.Governance
import Cardano.CLI.Types.TxFeature

import Data.Bifunctor (first)
import Data.Foldable
import Data.Function
import qualified Data.Map.Strict as Map
import Data.Maybe
import Data.Text (Text)
import GHC.Exts (IsList (..))
import Options.Applicative
import qualified Options.Applicative as Opt

Expand Down Expand Up @@ -64,6 +70,7 @@ pCompatibleSignedTransaction env sbe =
<*> many pWitnessSigningData
<*> optional (pNetworkId env)
<*> pTxFee
<*> many (pCertificateFile sbe ManualBalance)
<*> pOutputFile

pTxInOnly :: Parser TxIn
Expand Down Expand Up @@ -178,13 +185,15 @@ data CompatibleTransactionCmds era
(Maybe NetworkId)
!Coin
-- ^ Tx fee
![(CertificateFile, Maybe (ScriptWitnessFiles WitCtxStake))]
-- ^ stake registering certs
!(File () Out)

renderCompatibleTransactionCmd :: CompatibleTransactionCmds era -> Text
renderCompatibleTransactionCmd _ = ""

data CompatibleTransactionError
= CompatibleTxOutError !TxCmdError
= CompatibleTxCmdError !TxCmdError
| CompatibleWitnessError !ReadWitnessSigningDataError
| CompatiblePParamsConversionError !ProtocolParametersConversionError
| CompatibleBootstrapWitnessError !BootstrapWitnessError
Expand All @@ -193,10 +202,11 @@ data CompatibleTransactionError
| CompatibleProposalError !ProposalError
| CompatibleVoteError !VoteError
| forall era. CompatibleVoteMergeError !(VotesMergingConflict era)
| CompatibleScriptWitnessError !ScriptWitnessError

instance Error CompatibleTransactionError where
prettyError = \case
CompatibleTxOutError e -> renderTxCmdError e
CompatibleTxCmdError e -> renderTxCmdError e
CompatibleWitnessError e -> renderReadWitnessSigningDataError e
CompatiblePParamsConversionError e -> prettyError e
CompatibleBootstrapWitnessError e -> renderBootstrapWitnessError e
Expand All @@ -205,9 +215,12 @@ instance Error CompatibleTransactionError where
CompatibleProposalError e -> pshow e
CompatibleVoteError e -> pshow e
CompatibleVoteMergeError e -> pshow e
CompatibleScriptWitnessError e -> renderScriptWitnessError e

runCompatibleTransactionCmd
:: CompatibleTransactionCmds era -> ExceptT CompatibleTransactionError IO ()
:: forall era
. CompatibleTransactionCmds era
-> ExceptT CompatibleTransactionError IO ()
runCompatibleTransactionCmd
( CreateCompatibleSignedTransaction
sbe
Expand All @@ -219,12 +232,72 @@ runCompatibleTransactionCmd
witnesses
mNetworkId
fee
certificates
outputFp
) = do
sks <- firstExceptT CompatibleWitnessError $ mapM (newExceptT . readWitnessSigningData) witnesses

allOuts <- firstExceptT CompatibleTxOutError $ mapM (toTxOutInAnyEra sbe) outs
allOuts <- firstExceptT CompatibleTxCmdError $ mapM (toTxOutInAnyEra sbe) outs

certFilesAndMaybeScriptWits <-
firstExceptT CompatibleScriptWitnessError $
readScriptWitnessFiles sbe certificates

certsAndMaybeScriptWits :: [(Certificate era, Maybe (ScriptWitness WitCtxStake era))] <-
shelleyBasedEraConstraints sbe $
sequence
[ fmap
(,mSwit)
( firstExceptT CompatibleFileError . newExceptT $
readFileTextEnvelope AsCertificate (File certFile)
)
| (CertificateFile certFile, mSwit) <- certFilesAndMaybeScriptWits
]

(protocolUpdates, votes) :: (AnyProtocolUpdate era, AnyVote era) <-
caseShelleyToBabbageOrConwayEraOnwards
( const $ do
prop <- maybe (pure $ NoPParamsUpdate sbe) readUpdateProposalFile mUpdateProposal
return (prop, NoVotes)
)
( \w -> do
prop <- maybe (pure $ NoPParamsUpdate sbe) readProposalProcedureFile mProposalProcedure
votesAndWits <-
firstExceptT CompatibleVoteError . newExceptT $
readVotingProceduresFiles w mVotes
votingProcedures <-
firstExceptT CompatibleVoteMergeError . hoistEither $
mkTxVotingProcedures votesAndWits
return (prop, VotingProcedures w votingProcedures)
)
sbe

let certsRefInputs =
[ refInput
| (_, Just sWit) <- certsAndMaybeScriptWits
, refInput <- maybeToList $ getScriptWitnessReferenceInput sWit
]

votesRefInputs =
[ refInput
| VotingProcedures _ (TxVotingProcedures _ (BuildTxWith voteMap)) <- [votes]
, sWit <- Map.elems voteMap
, refInput <- maybeToList $ getScriptWitnessReferenceInput sWit
]

proposalsRefInputs =
[ refInput
| ProposalProcedures _ (TxProposalProcedures _ (BuildTxWith proposalMap)) <- [protocolUpdates]
, sWit <- Map.elems proposalMap
, refInput <- maybeToList $ getScriptWitnessReferenceInput sWit
]

validatedRefInputs <-
liftEither . first CompatibleTxCmdError . validateTxInsReference $
certsRefInputs <> votesRefInputs <> proposalsRefInputs
let txCerts = convertCertificates certsAndMaybeScriptWits

-- this body is only for witnesses
apiTxBody <-
firstExceptT CompatibleTxBodyError $
hoistEither $
Expand All @@ -233,39 +306,52 @@ runCompatibleTransactionCmd
& setTxIns (map (,BuildTxWith (KeyWitness KeyWitnessForSpending)) ins)
& setTxOuts allOuts
& setTxFee (TxFeeExplicit sbe fee)
& setTxCertificates txCerts
& setTxInsReference validatedRefInputs

let (sksByron, sksShelley) = partitionSomeWitnesses $ map categoriseSomeSigningWitness sks

byronWitnesses <-
firstExceptT CompatibleBootstrapWitnessError $
hoistEither (mkShelleyBootstrapWitnesses sbe mNetworkId apiTxBody sksByron)
firstExceptT CompatibleBootstrapWitnessError . hoistEither $
mkShelleyBootstrapWitnesses sbe mNetworkId apiTxBody sksByron

let newShelleyKeyWits = map (makeShelleyKeyWitness sbe apiTxBody) sksShelley
allKeyWits = newShelleyKeyWits ++ byronWitnesses

(protocolUpdates, votes) <-
caseShelleyToBabbageOrConwayEraOnwards
( const $ do
prop <- maybe (return $ NoPParamsUpdate sbe) readUpdateProposalFile mUpdateProposal
return (prop, NoVotes)
)
( \w -> do
prop <- maybe (return $ NoPParamsUpdate sbe) readProposalProcedureFile mProposalProcedure
votesAndWits <- firstExceptT CompatibleVoteError $ newExceptT $ readVotingProceduresFiles w mVotes
votingProcedures <-
firstExceptT CompatibleVoteMergeError $ hoistEither $ mkTxVotingProcedures votesAndWits
return (prop, VotingProcedures w votingProcedures)
)
sbe

signedTx <-
firstExceptT CompatiblePParamsConversionError . hoistEither $
-- FIXME https://github.com/IntersectMBO/cardano-cli/pull/972
createCompatibleSignedTx sbe ins allOuts allKeyWits fee protocolUpdates votes TxCertificatesNone
createCompatibleSignedTx sbe ins allOuts allKeyWits fee protocolUpdates votes txCerts

firstExceptT CompatibleFileError $
newExceptT $
writeTxFileTextEnvelopeCddl sbe outputFp signedTx
where
convertCertificates
:: [(Certificate era, Maybe (ScriptWitness WitCtxStake era))]
-> TxCertificates BuildTx era
convertCertificates certsAndScriptWitnesses =
TxCertificates sbe certs $ BuildTxWith reqWits
where
certs = map fst certsAndScriptWitnesses
reqWits = fromList $ mapMaybe convert' certsAndScriptWitnesses
convert'
:: (Certificate era, Maybe (ScriptWitness WitCtxStake era))
-> Maybe (StakeCredential, Witness WitCtxStake era)
convert' (cert, mScriptWitnessFiles) = do
sCred <- selectStakeCredentialWitness cert
Just . (sCred,) $ case mScriptWitnessFiles of
Just sWit -> ScriptWitness ScriptWitnessForStakeAddr sWit
Nothing -> KeyWitness KeyWitnessForStakeAddr

validateTxInsReference
:: [TxIn]
-> Either TxCmdError (TxInsReference era)
validateTxInsReference [] = return TxInsReferenceNone
validateTxInsReference allRefIns = do
let era = toCardanoEra era
eraMismatchError = Left $ TxCmdTxFeatureMismatch (anyCardanoEra era) TxFeatureReferenceInputs
w <- maybe eraMismatchError Right $ forEraMaybeEon era
pure $ TxInsReference w allRefIns

readUpdateProposalFile
:: Featured ShelleyToBabbageEra era (Maybe UpdateProposalFile)
Expand Down
21 changes: 6 additions & 15 deletions cardano-cli/src/Cardano/CLI/EraBased/Run/Transaction.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1227,12 +1227,12 @@ getAllReferenceInputs
votingProceduresAndMaybeScriptWits
propProceduresAnMaybeScriptWits
readOnlyRefIns = do
let txinsWitByRefInputs = [getReferenceInput sWit | (_, Just sWit) <- txins]
mintingRefInputs = map getReferenceInput mintWitnesses
certsWitByRefInputs = [getReferenceInput sWit | (_, Just sWit) <- certFiles]
withdrawalsWitByRefInputs = [getReferenceInput sWit | (_, _, Just sWit) <- withdrawals]
votesWitByRefInputs = [getReferenceInput sWit | (_, Just sWit) <- votingProceduresAndMaybeScriptWits]
propsWitByRefInputs = [getReferenceInput sWit | (_, Just sWit) <- propProceduresAnMaybeScriptWits]
let txinsWitByRefInputs = [getScriptWitnessReferenceInput sWit | (_, Just sWit) <- txins]
mintingRefInputs = map getScriptWitnessReferenceInput mintWitnesses
certsWitByRefInputs = [getScriptWitnessReferenceInput sWit | (_, Just sWit) <- certFiles]
withdrawalsWitByRefInputs = [getScriptWitnessReferenceInput sWit | (_, _, Just sWit) <- withdrawals]
votesWitByRefInputs = [getScriptWitnessReferenceInput sWit | (_, Just sWit) <- votingProceduresAndMaybeScriptWits]
propsWitByRefInputs = [getScriptWitnessReferenceInput sWit | (_, Just sWit) <- propProceduresAnMaybeScriptWits]

concatMap
catMaybes
Expand All @@ -1244,15 +1244,6 @@ getAllReferenceInputs
, propsWitByRefInputs
, map Just readOnlyRefIns
]
where
getReferenceInput
:: ScriptWitness witctx era -> Maybe TxIn
getReferenceInput sWit =
case sWit of
PlutusScriptWitness _ _ (PReferenceScript refIn) _ _ _ -> Just refIn
PlutusScriptWitness _ _ PScript{} _ _ _ -> Nothing
SimpleScriptWitness _ (SReferenceScript refIn) -> Just refIn
SimpleScriptWitness _ SScript{} -> Nothing

toAddressInAnyEra
:: CardanoEra era
Expand Down
Loading

0 comments on commit 3b889d3

Please sign in to comment.