Skip to content

Commit

Permalink
Make cardano-testnet Conway tests start after bootstrap
Browse files Browse the repository at this point in the history
  • Loading branch information
carbolymer committed May 15, 2024
1 parent 808830c commit 0eee585
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 303 deletions.
3 changes: 2 additions & 1 deletion cardano-testnet/src/Testnet/Defaults.hs
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,8 @@ eraToProtocolVersion (AnyCardanoEra era) =
AlonzoEra -> mkProtVer (6, 0)
-- Babbage had an intra-era hardfork
BabbageEra -> mkProtVer (8, 0)
ConwayEra -> mkProtVer (9, 0)
-- By default start after bootstrap (which is PV9)
ConwayEra -> mkProtVer (10, 0)

-- TODO: Expose from cardano-api
mkProtVer :: (Natural, Natural) -> ProtVer
Expand Down
20 changes: 0 additions & 20 deletions cardano-testnet/src/Testnet/Property/Util.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@ module Testnet.Property.Util
( integration
, integrationRetryWorkspace
, integrationWorkspace
, isBootstrapPhase
, isLinux
, runInBackground

, decodeEraUTxO
) where

import Cardano.Api
import Cardano.Api.ProtocolParameters (ProtocolParameters(..))

import Control.Exception.Safe (MonadCatch)
import Control.Monad
Expand All @@ -26,8 +24,6 @@ import qualified System.Environment as IO
import System.Info (os)
import qualified System.IO.Unsafe as IO

import Testnet.Process.Cli.Keys

import qualified Hedgehog as H
import qualified Hedgehog.Extras as H
import Hedgehog.Internal.Property (MonadTest)
Expand Down Expand Up @@ -79,19 +75,3 @@ runInBackground act = void . H.evalM $ allocate (H.async act) cleanUp

decodeEraUTxO :: (IsShelleyBasedEra era, MonadTest m) => ShelleyBasedEra era -> Aeson.Value -> m (UTxO era)
decodeEraUTxO _ = H.jsonErrorFail . Aeson.fromJSON

isBootstrapPhase
:: ( HasCallStack
, MonadIO m
, MonadTest m
, MonadCatch m
)
=> String
-> H.ExecConfig
-> m Bool
isBootstrapPhase eraName execConfig = do
ppJSON <-
execCliStdoutToJson execConfig [ eraName, "query", "protocol-parameters" ]
protocolParametersOut :: ProtocolParameters <- H.jsonErrorFail $ Aeson.fromJSON ppJSON
let (major, _minor) = protocolParamProtocolVersion protocolParametersOut
pure $ major == 9
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import Prelude

import Control.Monad
import qualified Data.Char as C
import Data.List (isInfixOf)
import qualified Data.Map as Map
import Data.Maybe.Strict
import Data.Set (Set)
Expand All @@ -43,7 +42,7 @@ import Testnet.Process.Cli.Keys
import qualified Testnet.Process.Cli.SPO as SPO
import Testnet.Process.Cli.Transaction
import Testnet.Process.Run (execCli', execCliAny, mkExecConfig)
import Testnet.Property.Util (integrationWorkspace, isBootstrapPhase)
import Testnet.Property.Util (integrationWorkspace)
import Testnet.Types

import Hedgehog
Expand Down Expand Up @@ -173,81 +172,73 @@ hprop_constitutional_committee_add_new = integrationWorkspace "constitutional-co

signedProposalTx <-
signTx execConfig cEra work "signed-proposal" (File txbodyFp) [SomeKeyPair $ paymentKeyInfoPair wallet0]
bootstrapPhase <- isBootstrapPhase eraName execConfig
if bootstrapPhase then do
(_code, _out, err) <- execCliAny execConfig
[ eraName, "transaction", "submit"
, "--tx-file", unFile signedProposalTx
]
assert ("DisallowedProposalDuringBootstrap" `isInfixOf` err)
else do

submitTx execConfig cEra signedProposalTx

governanceActionTxId <- H.noteM $ retrieveTransactionId execConfig signedProposalTx

governanceActionIx <-
H.nothingFailM .
H.leftFailM $
findCondition
(maybeExtractGovernanceActionIndex (fromString governanceActionTxId))
configurationFile
socketPath
deadlineEpoch

dRepVoteFiles <-
DRep.generateVoteFiles
execConfig work "vote-files" governanceActionTxId governanceActionIx
[(defaultDRepKeyPair idx, vote) | (vote, idx) <- drepVotes]

spoVoteFiles <-
SPO.generateVoteFiles
ceo execConfig work "vote-files" governanceActionTxId governanceActionIx
[(poolKeys, vote) | (vote, _idx) <- spoVotes]

let voteFiles = dRepVoteFiles <> spoVoteFiles

voteTxBodyFp <-
DRep.createVotingTxBody
execConfig epochStateView sbe work "vote-tx-body" voteFiles wallet0

-- FIXME: remove dependence of signTx on PaymentKeyPair
let poolNodePaymentKeyPair = KeyPair
{ signingKey = File . signingKeyFp $ poolNodeKeysCold poolKeys
, verificationKey = error "unused"
}
drepSKeys = map (defaultDRepKeyPair . snd) drepVotes
signingKeys = SomeKeyPair <$> paymentKeyInfoPair wallet0:poolNodePaymentKeyPair:drepSKeys
voteTxFp <- signTx
execConfig cEra gov "signed-vote-tx" voteTxBodyFp signingKeys

submitTx execConfig cEra voteTxFp

_ <- waitForEpochs epochStateView (L.EpochInterval 1)

govState <- getGovState epochStateView ceo
govActionState <- H.headM $ govState ^. L.cgsProposalsL . L.pPropsL . to toList
let gaDRepVotes = govActionState ^. L.gasDRepVotesL . to toList
gaSpoVotes = govActionState ^. L.gasStakePoolVotesL . to toList

length (filter ((== L.VoteYes) . snd) gaDRepVotes) === 5
length (filter ((== L.VoteNo) . snd) gaDRepVotes) === 3
length (filter ((== L.Abstain) . snd) gaDRepVotes) === 2
length drepVotes === length gaDRepVotes
length (filter ((== L.VoteYes) . snd) gaSpoVotes) === 1
length spoVotes === length gaSpoVotes

H.nothingFailM . H.leftFailM $
findCondition committeeIsPresent configurationFile socketPath deadlineEpoch

-- show proposed committe meembers
H.noteShow_ ccCredentials

newCommitteeMembers :: Set (L.Credential L.ColdCommitteeRole L.StandardCrypto)
<- fromList <$> getCommitteeMembers epochStateView ceo

-- check that the committee is actually what we expect
newCommitteeMembers === fromList ccCredentials

submitTx execConfig cEra signedProposalTx

governanceActionTxId <- H.noteM $ retrieveTransactionId execConfig signedProposalTx

governanceActionIx <-
H.nothingFailM .
H.leftFailM $
findCondition
(maybeExtractGovernanceActionIndex (fromString governanceActionTxId))
configurationFile
socketPath
deadlineEpoch

dRepVoteFiles <-
DRep.generateVoteFiles
execConfig work "vote-files" governanceActionTxId governanceActionIx
[(defaultDRepKeyPair idx, vote) | (vote, idx) <- drepVotes]

spoVoteFiles <-
SPO.generateVoteFiles
ceo execConfig work "vote-files" governanceActionTxId governanceActionIx
[(poolKeys, vote) | (vote, _idx) <- spoVotes]

let voteFiles = dRepVoteFiles <> spoVoteFiles

voteTxBodyFp <-
DRep.createVotingTxBody
execConfig epochStateView sbe work "vote-tx-body" voteFiles wallet0

-- FIXME: remove dependence of signTx on PaymentKeyPair
let poolNodePaymentKeyPair = KeyPair
{ signingKey = File . signingKeyFp $ poolNodeKeysCold poolKeys
, verificationKey = error "unused"
}
drepSKeys = map (defaultDRepKeyPair . snd) drepVotes
signingKeys = SomeKeyPair <$> paymentKeyInfoPair wallet0:poolNodePaymentKeyPair:drepSKeys
voteTxFp <- signTx
execConfig cEra gov "signed-vote-tx" voteTxBodyFp signingKeys

submitTx execConfig cEra voteTxFp

_ <- waitForEpochs epochStateView (L.EpochInterval 1)

govState <- getGovState epochStateView ceo
govActionState <- H.headM $ govState ^. L.cgsProposalsL . L.pPropsL . to toList
let gaDRepVotes = govActionState ^. L.gasDRepVotesL . to toList
gaSpoVotes = govActionState ^. L.gasStakePoolVotesL . to toList

length (filter ((== L.VoteYes) . snd) gaDRepVotes) === 5
length (filter ((== L.VoteNo) . snd) gaDRepVotes) === 3
length (filter ((== L.Abstain) . snd) gaDRepVotes) === 2
length drepVotes === length gaDRepVotes
length (filter ((== L.VoteYes) . snd) gaSpoVotes) === 1
length spoVotes === length gaSpoVotes

H.nothingFailM . H.leftFailM $
findCondition committeeIsPresent configurationFile socketPath deadlineEpoch

-- show proposed committe meembers
H.noteShow_ ccCredentials

newCommitteeMembers :: Set (L.Credential L.ColdCommitteeRole L.StandardCrypto)
<- fromList <$> getCommitteeMembers epochStateView ceo

-- check that the committee is actually what we expect
newCommitteeMembers === fromList ccCredentials

parseKeyHashCred :: MonadFail m => String -> m (L.Credential kr L.StandardCrypto)
parseKeyHashCred hash = L.parseCredential $ "keyHash-" <> Text.pack (trim hash)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import Prelude
import Control.Monad
import Control.Monad.Catch (MonadCatch)
import Data.Data (Typeable)
import Data.List (isInfixOf)
import qualified Data.Map as Map
import Data.String
import qualified Data.Text as Text
Expand All @@ -40,11 +39,11 @@ import Testnet.EpochStateProcessing (watchEpochStateView)
import Testnet.Process.Cli.DRep
import Testnet.Process.Cli.Keys
import Testnet.Process.Cli.Transaction
import Testnet.Process.Run (execCli', execCliAny, mkExecConfig)
import Testnet.Property.Util (integrationWorkspace, isBootstrapPhase)
import Testnet.Process.Run (execCli', mkExecConfig)
import Testnet.Property.Util (integrationWorkspace)
import Testnet.Types

import Hedgehog (MonadTest, Property, annotateShow, assert)
import Hedgehog (MonadTest, Property, annotateShow)
import qualified Hedgehog.Extras as H

-- | Execute me with:
Expand All @@ -67,7 +66,6 @@ hprop_check_drep_activity = integrationWorkspace "test-activity" $ \tempAbsBaseP
, cardanoNodeEra = cEra
, cardanoNumDReps = 1
}
eraName = eraToString era

TestnetRuntime
{ testnetMagic
Expand Down Expand Up @@ -103,11 +101,10 @@ hprop_check_drep_activity = integrationWorkspace "test-activity" $ \tempAbsBaseP
maxEpochsToWaitAfterProposal = EpochInterval 2 -- If it takes more than 2 epochs we give up in any case.
firstTargetDRepActivity = EpochInterval 3

bootstrapPhase <- isBootstrapPhase eraName execConfig
void $ activityChangeProposalTest execConfig epochStateView configurationFile socketPath ceo gov
"firstProposal" wallet0 [(1, "yes")] firstTargetDRepActivity
minEpochsToWaitIfChanging (Just firstTargetDRepActivity)
maxEpochsToWaitAfterProposal bootstrapPhase
maxEpochsToWaitAfterProposal

-- Now we register two new DReps
drep2 <- registerDRep execConfig epochStateView ceo work "drep2" wallet1
Expand All @@ -130,7 +127,7 @@ hprop_check_drep_activity = integrationWorkspace "test-activity" $ \tempAbsBaseP
void $ activityChangeProposalTest execConfig epochStateView configurationFile socketPath ceo gov
"failingProposal" wallet2 [(1, "yes")] secondTargetDRepActivity
minEpochsToWaitIfNotChanging (Just firstTargetDRepActivity)
maxEpochsToWaitAfterProposal bootstrapPhase
maxEpochsToWaitAfterProposal

-- We now send a bunch of proposals to make sure that the 2 new DReps expire.
-- because DReps won't expire if there is not enough activity (opportunites to participate).
Expand All @@ -141,7 +138,7 @@ hprop_check_drep_activity = integrationWorkspace "test-activity" $ \tempAbsBaseP
("fillerProposalNum" ++ show proposalNum) wallet [(1, "yes")]
(EpochInterval (unEpochInterval secondTargetDRepActivity + fromIntegral proposalNum))
minEpochsToWaitIfNotChanging Nothing
maxEpochsToWaitAfterProposal bootstrapPhase
maxEpochsToWaitAfterProposal
| (proposalNum, wallet) <- zip [1..numOfFillerProposals] (cycle [wallet0, wallet1, wallet2])]

(EpochNo epochAfterTimeout) <- getCurrentEpochNo epochStateView
Expand All @@ -153,7 +150,7 @@ hprop_check_drep_activity = integrationWorkspace "test-activity" $ \tempAbsBaseP
void $ activityChangeProposalTest execConfig epochStateView configurationFile socketPath ceo gov
"lastProposal" wallet0 [(1, "yes")] lastTargetDRepActivity
minEpochsToWaitIfChanging (Just lastTargetDRepActivity)
maxEpochsToWaitAfterProposal bootstrapPhase
maxEpochsToWaitAfterProposal

-- | This function creates a proposal to change the DRep activity interval
-- and issues the specified votes using default DReps. Optionally, it also
Expand All @@ -178,11 +175,9 @@ activityChangeProposalTest
-- the proposal.
-> EpochInterval -- ^ The maximum number of epochs to wait for the DRep activity interval to
-- become expected value.
-> Bool -- ^ Flag to indicate if we are in bootstrap phase
-> m (String, Word32) -- ^ The transaction id and the index of the governance action.
activityChangeProposalTest execConfig epochStateView configurationFile socketPath ceo work prefix
wallet votes change minWait mExpected maxWait@(EpochInterval maxWaitNum)
bootstrapPhase = do
wallet votes change minWait mExpected maxWait@(EpochInterval maxWaitNum) = do
let sbe = conwayEraOnwardsToShelleyBasedEra ceo

mPreviousProposalInfo <- getLastPParamUpdateActionId execConfig
Expand All @@ -200,16 +195,14 @@ activityChangeProposalTest execConfig epochStateView configurationFile socketPat
ceo baseDir "proposal" mPreviousProposalInfo change wallet (epochBeforeProp + fromIntegral maxWaitNum)

voteChangeProposal execConfig epochStateView sbe baseDir "vote"
governanceActionTxId governanceActionIndex propVotes wallet bootstrapPhase
governanceActionTxId governanceActionIndex propVotes wallet

unless bootstrapPhase $ do
(EpochNo epochAfterProp) <- getCurrentEpochNo epochStateView
H.note_ $ "Epoch after \"" <> prefix <> "\" prop: " <> show epochAfterProp
(EpochNo epochAfterProp) <- getCurrentEpochNo epochStateView
H.note_ $ "Epoch after \"" <> prefix <> "\" prop: " <> show epochAfterProp

void $ waitForEpochs epochStateView minWait
case mExpected of
Nothing -> return ()
Just expected -> H.nothingFailM $ watchEpochStateView epochStateView (isDRepActivityUpdated expected) maxWait
void $ waitForEpochs epochStateView minWait
forM_ mExpected $ \expected ->
H.nothingFailM $ watchEpochStateView epochStateView (isDRepActivityUpdated expected) maxWait

return thisProposal

Expand Down Expand Up @@ -334,14 +327,12 @@ voteChangeProposal
-- of the default DRep that will make the vote and the type of the vote
-- (i.e: "yes", "no", "abstain").
-> PaymentKeyInfo -- ^ Wallet that will pay for the transaction.
-> Bool -- ^ Flag to indicate if we are in bootstrap phase
-> m ()
voteChangeProposal execConfig epochStateView sbe work prefix governanceActionTxId governanceActionIndex votes wallet bootstrapPhase = do
voteChangeProposal execConfig epochStateView sbe work prefix governanceActionTxId governanceActionIndex votes wallet = do
baseDir <- H.createDirectoryIfMissing $ work </> prefix

let era = toCardanoEra sbe
cEra = AnyCardanoEra era
eraName = eraToString era

voteFiles <- generateVoteFiles execConfig baseDir "vote-files"
governanceActionTxId governanceActionIndex
Expand All @@ -353,11 +344,4 @@ voteChangeProposal execConfig epochStateView sbe work prefix governanceActionTxI
let signingKeys = SomeKeyPair <$> (paymentKeyInfoPair wallet:(defaultDRepKeyPair . snd <$> votes))
voteTxFp <- signTx execConfig cEra baseDir "signed-vote-tx" voteTxBodyFp signingKeys

if bootstrapPhase then do
(_code, _out, err) <- execCliAny execConfig
[ eraName, "transaction", "submit"
, "--tx-file", unFile voteTxFp
]
assert ("DisallowedVotesDuringBootstrap" `isInfixOf` err)
else do
submitTx execConfig cEra voteTxFp
submitTx execConfig cEra voteTxFp
Loading

0 comments on commit 0eee585

Please sign in to comment.