Skip to content

Commit

Permalink
Organize voting code in ProposeNewConstitution test
Browse files Browse the repository at this point in the history
  • Loading branch information
palas committed Apr 23, 2024
1 parent 4a500fa commit e1654ac
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 47 deletions.
88 changes: 87 additions & 1 deletion cardano-testnet/src/Testnet/Components/DReps.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ module Testnet.Components.DReps
( generateDRepKeyPair
, generateRegistrationCertificate
, createDRepRegistrationTxBody
, generateVoteFiles
, createVotingTxBody
, signTx
, submitTx
, failToSubmitTx
Expand All @@ -17,10 +19,11 @@ import Cardano.CLI.Types.Common (File (..))

import Prelude

import Control.Monad (void)
import Control.Monad (forM, void)
import Control.Monad.Catch (MonadCatch)
import Control.Monad.IO.Class (MonadIO)
import qualified Data.Text as Text
import Data.Word (Word32)
import GHC.IO.Exception (ExitCode (..))
import GHC.Stack (HasCallStack)
import qualified GHC.Stack as GHC
Expand Down Expand Up @@ -140,6 +143,89 @@ createDRepRegistrationTxBody execConfig epochStateView sbe work prefix drepRegCe
]
return dRepRegistrationTxBody

-- DRep vote file generation
data DRepVoteFile

-- | Generates decentralized representative (DRep) voting files (without signing)
-- using @cardano-cli@.
--
-- This function takes the following parameters:
--
-- * 'execConfig': Specifies the CLI execution configuration.
-- * 'work': Base directory path where the voting files and directories will be
-- stored.
-- * 'prefix': Name for the subfolder that will be created under 'work' to store
-- the output voting files.
-- * 'governanceActionTxId': Transaction ID string of the governance action.
-- * 'governanceActionIndex': Index of the governance action.
-- * 'allVotes': List of tuples where each tuple contains a 'PaymentKeyPair'
-- representing the DRep key pair and a 'String' representing the
-- vote type (i.e: "yes", "no", or "abstain").
--
-- Returns a list of generated @File DRepVoteFile In@ representing the paths to
-- the generated voting files.
generateVoteFiles :: (MonadTest m, MonadIO m, MonadCatch m)
=> H.ExecConfig
-> FilePath
-> String
-> String
-> Word32
-> [(PaymentKeyPair, [Char])]
-> m [File DRepVoteFile In]
generateVoteFiles execConfig work prefix governanceActionTxId governanceActionIndex allVotes = do
baseDir <- H.createDirectoryIfMissing $ work </> prefix
forM (zip [(1 :: Integer)..] allVotes) $ \(idx, (drepKeyPair, vote)) -> do
let path = File (baseDir </> "vote-" <> show idx)
void $ H.execCli' execConfig
[ "conway", "governance", "vote", "create"
, "--" ++ vote
, "--governance-action-tx-id", governanceActionTxId
, "--governance-action-index", show @Word32 governanceActionIndex
, "--drep-verification-key-file", paymentVKey drepKeyPair
, "--out-file", unFile path
]
return path

-- | Composes a decentralized representative (DRep) voting transaction body
-- (without signing) using @cardano-cli@.
--
-- This function takes seven parameters:
--
-- * 'execConfig': Specifies the CLI execution configuration.
-- * 'epochStateView': Current epoch state view for transaction building. It can be obtained
-- using the 'getEpochStateView' function.
-- * 'sbe': The Shelley-based era (e.g., 'ShelleyEra') in which the transaction will be constructed.
-- * 'work': Base directory path where the transaction body file will be stored.
-- * 'prefix': Prefix for the output transaction body file name. The extension will be @.txbody@.
-- * 'votes': List of voting files (@File DRepVoteFile In@) to include in the transaction,
-- obtained using 'generateVoteFiles'.
-- * 'wallet': Payment key information associated with the transaction,
-- as returned by 'cardanoTestnetDefault'.
--
-- Returns the generated @File TxBody In@ file path to the transaction body.
createVotingTxBody
:: (H.MonadAssertion m, MonadTest m, MonadCatch m, MonadIO m)
=> H.ExecConfig
-> EpochStateView
-> ShelleyBasedEra era
-> FilePath
-> String
-> [File DRepVoteFile In]
-> PaymentKeyInfo
-> m (File TxBody In)
createVotingTxBody execConfig epochStateView sbe work prefix votes wallet = do
let dRepVotingTxBody = File (work </> prefix <> ".txbody")
walletLargestUTXO <- findLargestUtxoForPaymentKey epochStateView sbe wallet
void $ H.execCli' execConfig $
[ "conway", "transaction", "build"
, "--change-address", Text.unpack $ paymentKeyInfoAddr wallet
, "--tx-in", Text.unpack $ renderTxIn walletLargestUTXO
] ++ (concat [["--vote-file", voteFile] | File voteFile <- votes]) ++
[ "--witness-override", show @Int (length votes)
, "--out-file", unFile dRepVotingTxBody
]
return dRepVotingTxBody

-- Transaction signing

data SignedTx
Expand Down
6 changes: 6 additions & 0 deletions cardano-testnet/src/Testnet/Defaults.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module Testnet.Defaults
, defaultConwayGenesis
, defaultDRepVkeyFp
, defaultDRepSkeyFp
, defaultDRepKeyPair
, defaultShelleyGenesis
, defaultGenesisFilepath
, defaultYamlHardforkViaConfig
Expand Down Expand Up @@ -70,6 +71,7 @@ import Numeric.Natural
import System.FilePath ((</>))

import Test.Cardano.Ledger.Core.Rational
import Testnet.Runtime (PaymentKeyPair (PaymentKeyPair))
import Testnet.Start.Types

{- HLINT ignore "Use underscore" -}
Expand Down Expand Up @@ -508,6 +510,10 @@ defaultDRepSkeyFp
-> FilePath
defaultDRepSkeyFp n = "drep-keys" </> ("drep" <> show n) </> "drep.skey"

-- | The relative path to DRep key pairs in directories created by cardano-testnet
defaultDRepKeyPair :: Int -> PaymentKeyPair
defaultDRepKeyPair n = PaymentKeyPair (defaultDRepVkeyFp n) (defaultDRepSkeyFp n)

-- TODO: We should not hardcode a script like this. We need to move
-- plutus-example from plutus apps to cardano-node-testnet. This will
-- let us directly compile the plutus validators and avoid bit rotting of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ import Data.Maybe.Strict
import Data.String
import Data.Text (Text)
import qualified Data.Text as Text
import Data.Word
import GHC.Stack (callStack)
import Lens.Micro
import System.FilePath ((</>))

import Testnet.Components.Configuration
import Testnet.Components.DReps (createVotingTxBody, generateVoteFiles, signTx, submitTx)
import Testnet.Components.Query
import Testnet.Components.TestWatchdog
import Testnet.Defaults
Expand Down Expand Up @@ -104,9 +104,9 @@ hprop_ledger_events_propose_new_constitution = H.integrationWorkspace "propose-n

-- Create Conway constitution
gov <- H.createDirectoryIfMissing $ work </> "governance"
proposalAnchorFile <- H.note $ work </> gov </> "sample-proposal-anchor"
consitutionFile <- H.note $ work </> gov </> "sample-constitution"
constitutionActionFp <- H.note $ work </> gov </> "constitution.action"
proposalAnchorFile <- H.note $ gov </> "sample-proposal-anchor"
consitutionFile <- H.note $ gov </> "sample-constitution"
constitutionActionFp <- H.note $ gov </> "constitution.action"

H.writeFile proposalAnchorFile "dummy anchor data"
H.writeFile consitutionFile "dummy constitution data"
Expand Down Expand Up @@ -179,12 +179,12 @@ hprop_ledger_events_propose_new_constitution = H.integrationWorkspace "propose-n
, "--tx-file", txbodySignedFp
]

txidString <- mconcat . lines <$> H.execCli' execConfig
governanceActionTxId <- mconcat . lines <$> H.execCli' execConfig
[ "transaction", "txid"
, "--tx-file", txbodySignedFp
]

!propSubmittedResult <- findCondition (maybeExtractGovernanceActionIndex sbe (fromString txidString))
!propSubmittedResult <- findCondition (maybeExtractGovernanceActionIndex sbe (fromString governanceActionTxId))
configurationFile
socketPath
(EpochNo 10)
Expand All @@ -197,50 +197,18 @@ hprop_ledger_events_propose_new_constitution = H.integrationWorkspace "propose-n
H.failMessage callStack "Couldn't find proposal."
Right (Just a) -> return a

let voteFp :: Int -> FilePath
voteFp n = work </> gov </> "vote-" <> show n

-- Proposal was successfully submitted, now we vote on the proposal and confirm it was ratified
forM_ allVotes $ \(vote, n) -> do
H.execCli' execConfig
[ "conway", "governance", "vote", "create"
, "--" ++ vote
, "--governance-action-tx-id", txidString
, "--governance-action-index", show @Word32 governanceActionIndex
, "--drep-verification-key-file", defaultDRepVkeyFp n
, "--out-file", voteFp n
]

-- We need more UTxOs

txin3 <- findLargestUtxoForPaymentKey epochStateView sbe wallet0

voteTxFp <- H.note $ work </> gov </> "vote.tx"
voteTxBodyFp <- H.note $ work </> gov </> "vote.txbody"
voteFiles <- generateVoteFiles execConfig work "vote-files"
governanceActionTxId governanceActionIndex
[(defaultDRepKeyPair idx, vote) | (vote, idx) <- allVotes]

-- Submit votes
void $ H.execCli' execConfig $
[ "conway", "transaction", "build"
, "--change-address", Text.unpack $ paymentKeyInfoAddr wallet0
, "--tx-in", Text.unpack $ renderTxIn txin3
, "--tx-out", Text.unpack (paymentKeyInfoAddr wallet1) <> "+" <> show @Int 3_000_000
] ++ (concat [["--vote-file", voteFp n] | (_, n) <- allVotes]) ++
[ "--witness-override", show @Int (numVotes + 1)
, "--out-file", voteTxBodyFp
]

void $ H.execCli' execConfig $
[ "conway", "transaction", "sign"
, "--tx-body-file", voteTxBodyFp
, "--signing-key-file", paymentSKey $ paymentKeyInfoPair wallet0
] ++ (concat [["--signing-key-file", defaultDRepSkeyFp n] | (_, n) <- allVotes]) ++
[ "--out-file", voteTxFp
]
voteTxBodyFp <- createVotingTxBody execConfig epochStateView sbe work "vote-tx-body"
voteFiles wallet0

void $ H.execCli' execConfig
[ "conway", "transaction", "submit"
, "--tx-file", voteTxFp
]
voteTxFp <- signTx execConfig cEra gov "signed-vote-tx" voteTxBodyFp
(paymentKeyInfoPair wallet0:[defaultDRepKeyPair n | (_, n) <- allVotes])
submitTx execConfig cEra voteTxFp

-- We check that constitution was succcessfully ratified

Expand Down

0 comments on commit e1654ac

Please sign in to comment.